fix: stabilize market metrics hydration and sorting

This commit is contained in:
2026-04-23 14:35:14 +08:00
parent a51c6f7bf2
commit 233de28713
7 changed files with 362 additions and 45 deletions
+36 -20
View File
@@ -10,6 +10,7 @@ interface ExportRangeControllerOptions {
onProgress?: (state: { currentPage: number; totalPages?: number }) => void;
prepareCurrentPageForExport(): Promise<void>;
readCurrentPageRecords(): MarketRecord[];
readCurrentPageRowCount(): number;
window: Window;
}
@@ -26,13 +27,10 @@ export function createExportRangeController(options: ExportRangeControllerOption
currentPage,
totalPages: target.mode === "count" ? target.pageCount : undefined
});
const currentPageReady = await waitForCurrentPageReady(expectedMinimumRowCount);
if (!currentPageReady) {
const currentPageRecords = await preparePageRecords(expectedMinimumRowCount);
if (!currentPageRecords) {
throw new Error(`${currentPage} 页加载超时,请稍后重试`);
}
await options.prepareCurrentPageForExport();
const currentPageRecords = options.readCurrentPageRecords();
currentPageRecords.forEach((record) => {
const existingRecord = mergedRecords.get(record.authorId);
mergedRecords.set(record.authorId, mergeMarketRecord(existingRecord, record));
@@ -63,6 +61,33 @@ export function createExportRangeController(options: ExportRangeControllerOption
}
};
async function preparePageRecords(
expectedMinimumRowCount: number | undefined
): Promise<MarketRecord[] | null> {
for (let attempt = 0; attempt < 4; attempt += 1) {
const currentPageReady = await waitForCurrentPageReady();
if (!currentPageReady) {
return null;
}
await options.prepareCurrentPageForExport();
const currentPageRecords = options.readCurrentPageRecords();
if (
currentPageRecords.length > 0 &&
(
typeof expectedMinimumRowCount !== "number" ||
expectedMinimumRowCount <= 0 ||
isCurrentPageTerminal() ||
currentPageRecords.length >= expectedMinimumRowCount
)
) {
return currentPageRecords;
}
}
return null;
}
async function waitForPageChange(previousSignature: string): Promise<boolean> {
const previousPageState = parsePageSignature(previousSignature);
@@ -82,9 +107,7 @@ export function createExportRangeController(options: ExportRangeControllerOption
return false;
}
async function waitForCurrentPageReady(
expectedMinimumRowCount: number | undefined
): Promise<boolean> {
async function waitForCurrentPageReady(): Promise<boolean> {
let stableAttemptCount = 0;
let lastReadyFingerprint = "";
@@ -101,17 +124,6 @@ export function createExportRangeController(options: ExportRangeControllerOption
continue;
}
if (
typeof expectedMinimumRowCount === "number" &&
expectedMinimumRowCount > 0 &&
!pageState.isTerminalPage &&
pageState.rowCount < expectedMinimumRowCount
) {
stableAttemptCount = 0;
lastReadyFingerprint = "";
continue;
}
const readyFingerprint = [
pageState.pageToken,
pageState.authorIds,
@@ -146,9 +158,13 @@ export function createExportRangeController(options: ExportRangeControllerOption
authorIds: pageSignature.authorIds,
isTerminalPage: isPageControlDisabled(nextPageControl),
pageToken: pageSignature.pageToken,
rowCount: options.readCurrentPageRecords().length
rowCount: options.readCurrentPageRowCount()
};
}
function isCurrentPageTerminal(): boolean {
return isPageControlDisabled(findNextPageControl(options.document));
}
}
function parsePageSignature(signature: string): {