// Serialisiert asynchrone Aufgaben je `key` und koalesziert Wartende: // - Es läuft nie mehr als eine Aufgabe pro Key gleichzeitig. // - Kommen während eines Laufs weitere Aufrufe rein, wird GENAU EIN weiterer // Durchlauf nachgelagert (egal wie viele warten) — sie teilen sich dessen // Ergebnis. So sehen alle den jüngsten Stand, ohne einen Lauf-Sturm. // // Einsatz: teure, idempotente Vorgänge wie der Hugo-Build (siehe hugo.js). const state = new Map(); export function coalesce(key, fn) { let s = state.get(key); if (!s) { s = { running: false, rerun: false, fn, waiters: [] }; state.set(key, s); } s.fn = fn; // jüngste Variante gewinnt für den nächsten Lauf return new Promise((resolve, reject) => { s.waiters.push({ resolve, reject }); if (!s.running) drain(key); else s.rerun = true; }); } async function drain(key) { const s = state.get(key); s.running = true; try { do { s.rerun = false; const waiters = s.waiters; s.waiters = []; try { const r = await s.fn(); waiters.forEach((w) => w.resolve(r)); } catch (e) { waiters.forEach((w) => w.reject(e)); } } while (s.rerun); } finally { s.running = false; } }