/** * Load one keyed thing at a time, however many triggers ask for it. * * Calls for the key already loading share that load instead of starting their * own. A caller that knows the data changed (`fresh` — after "mark watched", * on reconnect, when a filter flips) must not be answered by a load that may * predate the change, so it gets exactly one re-run once the current load * ends, however many such callers there were. * * Exists because the series page loaded itself six times on every open — * `onMount`, a mount-time `$effect`, the reachability effect's first run and * navigation updates each started a full load — putting about six times a * dozen requests in flight at once. * * TRACES: UR-062 | DR-295 */ export interface CoalescedLoader { /** Load `key`. `fresh`: the caller knows the data changed. */ load(key: string, options?: { fresh?: boolean }): Promise; } interface InFlight { key: string; /** Settles when this load and any re-run it owes have finished. */ done: Promise; rerun: boolean; } export function createCoalescedLoader(run: (key: string) => Promise): CoalescedLoader { let inFlight: InFlight | null = null; return { load(key, options = {}) { if (inFlight && inFlight.key === key) { if (options.fresh) inFlight.rerun = true; return inFlight.done; } const entry: InFlight = { key, rerun: false, done: Promise.resolve() }; entry.done = (async () => { try { await run(key); while (entry.rerun) { entry.rerun = false; await run(key); } } finally { if (inFlight === entry) inFlight = null; } })(); inFlight = entry; return entry.done; }, }; }