import { invariant } from '../../../invariant'; interface Entry { timerId: TimeoutID; callback: () => void; } export interface AsyncMarshal { add: (fn: () => void) => void; flush: () => void; } export default () => { const entries: Entry[] = []; const execute = (timerId: TimeoutID) => { const index: number = entries.findIndex( (item): boolean => item.timerId === timerId, ); invariant(index !== -1, 'Could not find timer'); // delete in place const [entry] = entries.splice(index, 1); entry.callback(); }; const add = (fn: () => void) => { const timerId: TimeoutID = setTimeout(() => execute(timerId)); const entry: Entry = { timerId, callback: fn, }; entries.push(entry); }; const flush = () => { // nothing to flush if (!entries.length) { return; } const shallow: Entry[] = [...entries]; // clearing entries in case a callback adds some more callbacks entries.length = 0; shallow.forEach((entry: Entry) => { clearTimeout(entry.timerId); entry.callback(); }); }; return { add, flush }; };