UNPKG

@graphql-tools/load

Version:

A set of utils for faster development of GraphQL tools

113 lines (112 loc) • 3.53 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.useQueue = useQueue; exports.useSyncQueue = useSyncQueue; function isThenable(value) { return value != null && typeof value.then === 'function'; } function useQueue(options) { const tasks = []; const concurrency = options?.concurrency; return { add(fn) { tasks.push(fn); }, runAll() { const total = tasks.length; if (total === 0) { return; } const limit = concurrency ?? total; let index = 0; let activeCount = 0; let settledCount = 0; let failed = false; let resolveDone; let rejectDone; let donePromise; const ensureDonePromise = () => { if (!donePromise) { ({ promise: donePromise, resolve: resolveDone, reject: rejectDone, } = Promise.withResolvers()); } return donePromise; }; const onSettle = () => { settledCount++; if (failed) { return; } if (settledCount === total) { resolveDone?.(); return; } pump(); }; const pump = () => { while (!failed && activeCount < limit && index < total) { const task = tasks[index++]; activeCount++; let result; try { result = task(); } catch (error) { failed = true; activeCount--; // If callers are already awaiting the completion gate, reject it. // Otherwise keep the sync failure synchronous. if (rejectDone) { rejectDone(error); return; } throw error; } if (isThenable(result)) { // Only async work needs a completion gate; sync results stay sync. ensureDonePromise(); result.then(() => { activeCount--; onSettle(); }, error => { failed = true; activeCount--; rejectDone(error); }); } else { activeCount--; settledCount++; } } if (!failed && settledCount === total) { resolveDone?.(); } }; pump(); if (failed) { return donePromise; } if (settledCount === total) { return; } return ensureDonePromise(); }, }; } function useSyncQueue() { const queue = []; return { add(fn) { queue.push(fn); }, runAll() { for (const fn of queue) { fn(); } }, }; }