UNPKG

contentful-sdk-core

Version:
113 lines (111 loc) 3.11 kB
class AbortError extends Error { name = 'AbortError'; constructor() { super('Throttled function aborted'); } } /** * Throttle promise-returning/async/normal functions. * * It rate-limits function calls without discarding them, making it ideal for external API interactions where avoiding call loss is crucial. * * @returns A throttle function. * * Both the `limit` and `interval` options must be specified. * * @example * ``` * import pThrottle from './PThrottle'; * * const now = Date.now(); * * const throttle = pThrottle({ * limit: 2, * interval: 1000 * }); * * const throttled = throttle(async index => { * const secDiff = ((Date.now() - now) / 1000).toFixed(); * return `${index}: ${secDiff}s`; * }); * * for (let index = 1; index <= 6; index++) { * (async () => { * console.log(await throttled(index)); * })(); * } * //=> 1: 0s * //=> 2: 0s * //=> 3: 1s * //=> 4: 1s * //=> 5: 2s * //=> 6: 2s * ``` */ function pThrottle({ limit, interval, strict, onDelay }) { if (!Number.isFinite(limit)) { throw new TypeError('Expected `limit` to be a finite number'); } if (!Number.isFinite(interval)) { throw new TypeError('Expected `interval` to be a finite number'); } const queue = new Map(); let currentTick = 0; let activeCount = 0; function windowedDelay() { const now = Date.now(); if (now - currentTick > interval) { activeCount = 1; currentTick = now; return 0; } if (activeCount < limit) { activeCount++; } else { currentTick += interval; activeCount = 1; } return currentTick - now; } const getDelay = windowedDelay; return function (function_) { const throttled = function (...arguments_) { if (!throttled.isEnabled) { return (async () => function_.apply(this, arguments_))(); } let timeoutId; return new Promise((resolve, reject) => { const execute = () => { resolve(function_.apply(this, arguments_)); queue.delete(timeoutId); }; const delay = getDelay(); if (delay > 0) { timeoutId = setTimeout(execute, delay); queue.set(timeoutId, reject); onDelay?.(); } else { execute(); } }); }; throttled.abort = () => { for (const timeout of queue.keys()) { clearTimeout(timeout); queue.get(timeout)(new AbortError()); } queue.clear(); }; throttled.isEnabled = true; Object.defineProperty(throttled, 'queueSize', { get() { return queue.size; }, }); return throttled; }; } export { AbortError, pThrottle as default }; //# sourceMappingURL=pThrottle.js.map