perf(web): batch dashboard tile hydration
This commit is contained in:
parent
63b008095f
commit
de87464ef1
7 changed files with 518 additions and 40 deletions
|
|
@ -9,6 +9,7 @@ import {
|
|||
createDashboardTileBackoff,
|
||||
createDashboardRequestAborter,
|
||||
runDashboardHydrationQueue,
|
||||
runDashboardHydrationBatchQueue,
|
||||
runViewportAwareDashboardHydrationQueue,
|
||||
shouldPauseDashboardRefresh,
|
||||
splitDashboardHydrationItemsByVisibility,
|
||||
|
|
@ -121,6 +122,25 @@ describe("dashboard refresh lifecycle", () => {
|
|||
expect(maxActive).toBe(2);
|
||||
});
|
||||
|
||||
test("hydrates queued work in fixed-size batches", async () => {
|
||||
const batches: number[][] = [];
|
||||
|
||||
await runDashboardHydrationBatchQueue({
|
||||
batchSize: 3,
|
||||
hydrateBatch: (items) => {
|
||||
batches.push(items);
|
||||
},
|
||||
items: [1, 2, 3, 4, 5, 6, 7],
|
||||
signal: new AbortController().signal,
|
||||
});
|
||||
|
||||
expect(batches).toEqual([
|
||||
[1, 2, 3],
|
||||
[4, 5, 6],
|
||||
[7],
|
||||
]);
|
||||
});
|
||||
|
||||
test("hydrates visible items before deferred items and waits for idle", async () => {
|
||||
const calls: string[] = [];
|
||||
const idleReleases: Array<() => void> = [];
|
||||
|
|
|
|||
|
|
@ -152,10 +152,12 @@ export async function runDashboardHydrationQueue<TItem>(
|
|||
}
|
||||
|
||||
export interface DashboardViewportHydrationQueueOptions<TItem> {
|
||||
batchSize?: number;
|
||||
collectVisibleModelIds: () => Promise<ReadonlySet<string>>;
|
||||
concurrency: number;
|
||||
getModelId: (item: TItem) => string;
|
||||
hydrate: (item: TItem) => Promise<void> | void;
|
||||
hydrateBatch?: (items: TItem[]) => Promise<void> | void;
|
||||
items: TItem[];
|
||||
onAllItemsSettled?: () => void;
|
||||
onVisibleItemsSettled?: () => void;
|
||||
|
|
@ -175,12 +177,7 @@ export async function runViewportAwareDashboardHydrationQueue<TItem>(
|
|||
visibleModelIds,
|
||||
});
|
||||
|
||||
await runDashboardHydrationQueue({
|
||||
concurrency: options.concurrency,
|
||||
hydrate: options.hydrate,
|
||||
items: visible,
|
||||
signal: options.signal,
|
||||
});
|
||||
await runDashboardHydrationItems(options, visible);
|
||||
if (options.signal.aborted) return;
|
||||
options.onVisibleItemsSettled?.();
|
||||
|
||||
|
|
@ -192,13 +189,44 @@ export async function runViewportAwareDashboardHydrationQueue<TItem>(
|
|||
await options.waitForIdle();
|
||||
if (options.signal.aborted) return;
|
||||
|
||||
await runDashboardHydrationQueue({
|
||||
concurrency: options.concurrency,
|
||||
hydrate: options.hydrate,
|
||||
items: deferred,
|
||||
await runDashboardHydrationItems(options, deferred);
|
||||
options.onAllItemsSettled?.();
|
||||
}
|
||||
|
||||
async function runDashboardHydrationItems<TItem>(
|
||||
options: DashboardViewportHydrationQueueOptions<TItem>,
|
||||
items: TItem[],
|
||||
): Promise<void> {
|
||||
if (!options.hydrateBatch) {
|
||||
await runDashboardHydrationQueue({
|
||||
concurrency: options.concurrency,
|
||||
hydrate: options.hydrate,
|
||||
items,
|
||||
signal: options.signal,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await runDashboardHydrationBatchQueue({
|
||||
batchSize: options.batchSize ?? options.concurrency,
|
||||
hydrateBatch: options.hydrateBatch,
|
||||
items,
|
||||
signal: options.signal,
|
||||
});
|
||||
options.onAllItemsSettled?.();
|
||||
}
|
||||
|
||||
export async function runDashboardHydrationBatchQueue<TItem>(options: {
|
||||
batchSize: number;
|
||||
hydrateBatch: (items: TItem[]) => Promise<void> | void;
|
||||
items: TItem[];
|
||||
signal: AbortSignal;
|
||||
}): Promise<void> {
|
||||
const batchSize = Math.max(1, Math.floor(options.batchSize));
|
||||
|
||||
for (let index = 0; index < options.items.length; index += batchSize) {
|
||||
if (options.signal.aborted) return;
|
||||
await options.hydrateBatch(options.items.slice(index, index + batchSize));
|
||||
}
|
||||
}
|
||||
|
||||
export function splitDashboardHydrationItemsByVisibility<TItem>(options: {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue