UNPKG

p-queue-compat

Version:
629 lines (626 loc) 28.8 kB
function _classPrivateMethodInitSpec(e, a) { _checkPrivateRedeclaration(e, a), a.add(e); } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _classPrivateFieldInitSpec(e, t, a) { _checkPrivateRedeclaration(e, t), t.set(e, a); } function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); } function _classPrivateGetter(s, r, a) { return a(_assertClassBrand(s, r)); } function _classPrivateFieldGet(s, a) { return s.get(_assertClassBrand(s, a)); } function _classPrivateFieldSet(s, a, r) { return s.set(_assertClassBrand(s, a), r), r; } function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); } import { EventEmitter } from 'eventemitter3'; import pTimeout from "p-timeout-compat"; import PriorityQueue from './priority-queue.js'; /** Promise queue with concurrency control. */ var _carryoverIntervalCount = /*#__PURE__*/new WeakMap(); var _isIntervalIgnored = /*#__PURE__*/new WeakMap(); var _intervalCount = /*#__PURE__*/new WeakMap(); var _intervalCap = /*#__PURE__*/new WeakMap(); var _rateLimitedInInterval = /*#__PURE__*/new WeakMap(); var _rateLimitFlushScheduled = /*#__PURE__*/new WeakMap(); var _interval = /*#__PURE__*/new WeakMap(); var _intervalEnd = /*#__PURE__*/new WeakMap(); var _lastExecutionTime = /*#__PURE__*/new WeakMap(); var _intervalId = /*#__PURE__*/new WeakMap(); var _timeoutId = /*#__PURE__*/new WeakMap(); var _queue = /*#__PURE__*/new WeakMap(); var _queueClass = /*#__PURE__*/new WeakMap(); var _pending = /*#__PURE__*/new WeakMap(); var _concurrency = /*#__PURE__*/new WeakMap(); var _isPaused = /*#__PURE__*/new WeakMap(); var _idAssigner = /*#__PURE__*/new WeakMap(); var _runningTasks = /*#__PURE__*/new WeakMap(); var _PQueue_brand = /*#__PURE__*/new WeakSet(); export default class PQueue extends EventEmitter { constructor(options) { var _ref, _options$carryoverInt; super(); // eslint-disable-next-line @typescript-eslint/consistent-type-assertions _classPrivateMethodInitSpec(this, _PQueue_brand); _classPrivateFieldInitSpec(this, _carryoverIntervalCount, void 0); _classPrivateFieldInitSpec(this, _isIntervalIgnored, void 0); _classPrivateFieldInitSpec(this, _intervalCount, 0); _classPrivateFieldInitSpec(this, _intervalCap, void 0); _classPrivateFieldInitSpec(this, _rateLimitedInInterval, false); _classPrivateFieldInitSpec(this, _rateLimitFlushScheduled, false); _classPrivateFieldInitSpec(this, _interval, void 0); _classPrivateFieldInitSpec(this, _intervalEnd, 0); _classPrivateFieldInitSpec(this, _lastExecutionTime, 0); _classPrivateFieldInitSpec(this, _intervalId, void 0); _classPrivateFieldInitSpec(this, _timeoutId, void 0); _classPrivateFieldInitSpec(this, _queue, void 0); _classPrivateFieldInitSpec(this, _queueClass, void 0); _classPrivateFieldInitSpec(this, _pending, 0); // The `!` is needed because of https://github.com/microsoft/TypeScript/issues/32194 _classPrivateFieldInitSpec(this, _concurrency, void 0); _classPrivateFieldInitSpec(this, _isPaused, void 0); // Use to assign a unique identifier to a promise function, if not explicitly specified _classPrivateFieldInitSpec(this, _idAssigner, 1n); // Track currently running tasks for debugging _classPrivateFieldInitSpec(this, _runningTasks, new Map()); /** Get or set the default timeout for all tasks. Can be changed at runtime. Operations will throw a `TimeoutError` if they don't complete within the specified time. The timeout begins when the operation is dequeued and starts execution, not while it's waiting in the queue. @example ``` const queue = new PQueue({timeout: 5000}); // Change timeout for all future tasks queue.timeout = 10000; ``` */ _defineProperty(this, "timeout", void 0); options = { carryoverIntervalCount: false, intervalCap: Number.POSITIVE_INFINITY, interval: 0, concurrency: Number.POSITIVE_INFINITY, autoStart: true, queueClass: PriorityQueue, ...options }; if (!(typeof options.intervalCap === 'number' && options.intervalCap >= 1)) { var _options$intervalCap$, _options$intervalCap; throw new TypeError(`Expected \`intervalCap\` to be a number from 1 and up, got \`${(_options$intervalCap$ = (_options$intervalCap = options.intervalCap) === null || _options$intervalCap === void 0 ? void 0 : _options$intervalCap.toString()) !== null && _options$intervalCap$ !== void 0 ? _options$intervalCap$ : ''}\` (${typeof options.intervalCap})`); } if (options.interval === undefined || !(Number.isFinite(options.interval) && options.interval >= 0)) { var _options$interval$toS, _options$interval; throw new TypeError(`Expected \`interval\` to be a finite number >= 0, got \`${(_options$interval$toS = (_options$interval = options.interval) === null || _options$interval === void 0 ? void 0 : _options$interval.toString()) !== null && _options$interval$toS !== void 0 ? _options$interval$toS : ''}\` (${typeof options.interval})`); } // TODO: Remove this fallback in the next major version // eslint-disable-next-line @typescript-eslint/no-deprecated _classPrivateFieldSet(_carryoverIntervalCount, this, (_ref = (_options$carryoverInt = options.carryoverIntervalCount) !== null && _options$carryoverInt !== void 0 ? _options$carryoverInt : options.carryoverConcurrencyCount) !== null && _ref !== void 0 ? _ref : false); _classPrivateFieldSet(_isIntervalIgnored, this, options.intervalCap === Number.POSITIVE_INFINITY || options.interval === 0); _classPrivateFieldSet(_intervalCap, this, options.intervalCap); _classPrivateFieldSet(_interval, this, options.interval); _classPrivateFieldSet(_queue, this, new options.queueClass()); _classPrivateFieldSet(_queueClass, this, options.queueClass); this.concurrency = options.concurrency; if (options.timeout !== undefined && !(Number.isFinite(options.timeout) && options.timeout > 0)) { throw new TypeError(`Expected \`timeout\` to be a positive finite number, got \`${options.timeout}\` (${typeof options.timeout})`); } this.timeout = options.timeout; _classPrivateFieldSet(_isPaused, this, options.autoStart === false); _assertClassBrand(_PQueue_brand, this, _setupRateLimitTracking).call(this); } get concurrency() { return _classPrivateFieldGet(_concurrency, this); } set concurrency(newConcurrency) { if (!(typeof newConcurrency === 'number' && newConcurrency >= 1)) { throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${newConcurrency}\` (${typeof newConcurrency})`); } _classPrivateFieldSet(_concurrency, this, newConcurrency); _assertClassBrand(_PQueue_brand, this, _processQueue).call(this); } /** Updates the priority of a promise function by its id, affecting its execution order. Requires a defined concurrency limit to take effect. For example, this can be used to prioritize a promise function to run earlier. ```js import PQueue from 'p-queue'; const queue = new PQueue({concurrency: 1}); queue.add(async () => '🦄', {priority: 1}); queue.add(async () => '🦀', {priority: 0, id: '🦀'}); queue.add(async () => '🦄', {priority: 1}); queue.add(async () => '🦄', {priority: 1}); queue.setPriority('🦀', 2); ``` In this case, the promise function with `id: '🦀'` runs second. You can also deprioritize a promise function to delay its execution: ```js import PQueue from 'p-queue'; const queue = new PQueue({concurrency: 1}); queue.add(async () => '🦄', {priority: 1}); queue.add(async () => '🦀', {priority: 1, id: '🦀'}); queue.add(async () => '🦄'); queue.add(async () => '🦄', {priority: 0}); queue.setPriority('🦀', -1); ``` Here, the promise function with `id: '🦀'` executes last. */ setPriority(id, priority) { if (typeof priority !== 'number' || !Number.isFinite(priority)) { throw new TypeError(`Expected \`priority\` to be a finite number, got \`${priority}\` (${typeof priority})`); } _classPrivateFieldGet(_queue, this).setPriority(id, priority); } async add(function_, options = {}) { var _this$idAssigner, _this$idAssigner2, _options, _options$id; // In case `id` is not defined. (_options$id = (_options = options).id) !== null && _options$id !== void 0 ? _options$id : _options.id = (_classPrivateFieldSet(_idAssigner, this, (_this$idAssigner = _classPrivateFieldGet(_idAssigner, this), _this$idAssigner2 = _this$idAssigner++, _this$idAssigner)), _this$idAssigner2).toString(); options = { timeout: this.timeout, ...options }; return new Promise((resolve, reject) => { // Create a unique symbol for tracking this task const taskSymbol = Symbol(`task-${options.id}`); _classPrivateFieldGet(_queue, this).enqueue(async () => { var _this$pending3, _this$pending4, _options$priority; _classPrivateFieldSet(_pending, this, (_this$pending3 = _classPrivateFieldGet(_pending, this), _this$pending4 = _this$pending3++, _this$pending3)), _this$pending4; // Track this running task _classPrivateFieldGet(_runningTasks, this).set(taskSymbol, { id: options.id, priority: (_options$priority = options.priority) !== null && _options$priority !== void 0 ? _options$priority : 0, // Match priority-queue default startTime: Date.now(), timeout: options.timeout }); try { // Check abort signal - if aborted, need to decrement the counter // that was incremented in tryToStartAnother try { var _options$signal; (_options$signal = options.signal) === null || _options$signal === void 0 || _options$signal.throwIfAborted(); } catch (error) { // Decrement the counter that was already incremented if (!_classPrivateFieldGet(_isIntervalIgnored, this)) { var _this$intervalCount3, _this$intervalCount4; _classPrivateFieldSet(_intervalCount, this, (_this$intervalCount3 = _classPrivateFieldGet(_intervalCount, this), _this$intervalCount4 = _this$intervalCount3--, _this$intervalCount3)), _this$intervalCount4; } // Clean up tracking before throwing _classPrivateFieldGet(_runningTasks, this).delete(taskSymbol); throw error; } let operation = function_({ signal: options.signal }); if (options.timeout) { operation = pTimeout(Promise.resolve(operation), { milliseconds: options.timeout, message: `Task timed out after ${options.timeout}ms (queue has ${_classPrivateFieldGet(_pending, this)} running, ${_classPrivateFieldGet(_queue, this).size} waiting)` }); } if (options.signal) { operation = Promise.race([operation, _assertClassBrand(_PQueue_brand, this, _throwOnAbort).call(this, options.signal)]); } const result = await operation; resolve(result); this.emit('completed', result); } catch (error) { reject(error); this.emit('error', error); } finally { // Remove from running tasks _classPrivateFieldGet(_runningTasks, this).delete(taskSymbol); // Use queueMicrotask to prevent deep recursion while maintaining timing queueMicrotask(() => { _assertClassBrand(_PQueue_brand, this, _next).call(this); }); } }, options); this.emit('add'); _assertClassBrand(_PQueue_brand, this, _tryToStartAnother).call(this); }); } async addAll(functions, options) { return Promise.all(functions.map(async function_ => this.add(function_, options))); } /** Start (or resume) executing enqueued tasks within concurrency limit. No need to call this if queue is not paused (via `options.autoStart = false` or by `.pause()` method.) */ start() { if (!_classPrivateFieldGet(_isPaused, this)) { return this; } _classPrivateFieldSet(_isPaused, this, false); _assertClassBrand(_PQueue_brand, this, _processQueue).call(this); return this; } /** Put queue execution on hold. */ pause() { _classPrivateFieldSet(_isPaused, this, true); } /** Clear the queue. */ clear() { _classPrivateFieldSet(_queue, this, new (_classPrivateFieldGet(_queueClass, this))()); // Note: We don't clear #runningTasks as those tasks are still running // They will be removed when they complete in the finally block // Force synchronous update since clear() should have immediate effect _assertClassBrand(_PQueue_brand, this, _updateRateLimitState).call(this); } /** Can be called multiple times. Useful if you for example add additional items at a later time. @returns A promise that settles when the queue becomes empty. */ async onEmpty() { // Instantly resolve if the queue is empty if (_classPrivateFieldGet(_queue, this).size === 0) { return; } await _assertClassBrand(_PQueue_brand, this, _onEvent).call(this, 'empty'); } /** @returns A promise that settles when the queue size is less than the given limit: `queue.size < limit`. If you want to avoid having the queue grow beyond a certain size you can `await queue.onSizeLessThan()` before adding a new item. Note that this only limits the number of items waiting to start. There could still be up to `concurrency` jobs already running that this call does not include in its calculation. */ async onSizeLessThan(limit) { // Instantly resolve if the queue is empty. if (_classPrivateFieldGet(_queue, this).size < limit) { return; } await _assertClassBrand(_PQueue_brand, this, _onEvent).call(this, 'next', () => _classPrivateFieldGet(_queue, this).size < limit); } /** The difference with `.onEmpty` is that `.onIdle` guarantees that all work from the queue has finished. `.onEmpty` merely signals that the queue is empty, but it could mean that some promises haven't completed yet. @returns A promise that settles when the queue becomes empty, and all promises have completed; `queue.size === 0 && queue.pending === 0`. */ async onIdle() { // Instantly resolve if none pending and if nothing else is queued if (_classPrivateFieldGet(_pending, this) === 0 && _classPrivateFieldGet(_queue, this).size === 0) { return; } await _assertClassBrand(_PQueue_brand, this, _onEvent).call(this, 'idle'); } /** The difference with `.onIdle` is that `.onPendingZero` only waits for currently running tasks to finish, ignoring queued tasks. @returns A promise that settles when all currently running tasks have completed; `queue.pending === 0`. */ async onPendingZero() { if (_classPrivateFieldGet(_pending, this) === 0) { return; } await _assertClassBrand(_PQueue_brand, this, _onEvent).call(this, 'pendingZero'); } /** @returns A promise that settles when the queue becomes rate-limited due to intervalCap. */ async onRateLimit() { if (this.isRateLimited) { return; } await _assertClassBrand(_PQueue_brand, this, _onEvent).call(this, 'rateLimit'); } /** @returns A promise that settles when the queue is no longer rate-limited. */ async onRateLimitCleared() { if (!this.isRateLimited) { return; } await _assertClassBrand(_PQueue_brand, this, _onEvent).call(this, 'rateLimitCleared'); } /** @returns A promise that rejects when any task in the queue errors. Use with `Promise.race([queue.onError(), queue.onIdle()])` to fail fast on the first error while still resolving normally when the queue goes idle. Important: The promise returned by `add()` still rejects. You must handle each `add()` promise (for example, `.catch(() => {})`) to avoid unhandled rejections. @example ``` import PQueue from 'p-queue'; const queue = new PQueue({concurrency: 2}); queue.add(() => fetchData(1)).catch(() => {}); queue.add(() => fetchData(2)).catch(() => {}); queue.add(() => fetchData(3)).catch(() => {}); // Stop processing on first error try { await Promise.race([ queue.onError(), queue.onIdle() ]); } catch (error) { queue.pause(); // Stop processing remaining tasks console.error('Queue failed:', error); } ``` */ // eslint-disable-next-line @typescript-eslint/promise-function-async async onError() { return new Promise((_resolve, reject) => { const handleError = error => { this.off('error', handleError); reject(error); }; this.on('error', handleError); }); } /** Size of the queue, the number of queued items waiting to run. */ get size() { return _classPrivateFieldGet(_queue, this).size; } /** Size of the queue, filtered by the given options. For example, this can be used to find the number of items remaining in the queue with a specific priority level. */ sizeBy(options) { // eslint-disable-next-line unicorn/no-array-callback-reference return _classPrivateFieldGet(_queue, this).filter(options).length; } /** Number of running items (no longer in the queue). */ get pending() { return _classPrivateFieldGet(_pending, this); } /** Whether the queue is currently paused. */ get isPaused() { return _classPrivateFieldGet(_isPaused, this); } /** Whether the queue is currently rate-limited due to intervalCap. */ get isRateLimited() { return _classPrivateFieldGet(_rateLimitedInInterval, this); } /** Whether the queue is saturated. Returns `true` when: - All concurrency slots are occupied and tasks are waiting, OR - The queue is rate-limited and tasks are waiting Useful for detecting backpressure and potential hanging tasks. ```js import PQueue from 'p-queue'; const queue = new PQueue({concurrency: 2}); // Backpressure handling if (queue.isSaturated) { console.log('Queue is saturated, waiting for capacity...'); await queue.onSizeLessThan(queue.concurrency); } // Monitoring for stuck tasks setInterval(() => { if (queue.isSaturated) { console.warn(`Queue saturated: ${queue.pending} running, ${queue.size} waiting`); } }, 60000); ``` */ get isSaturated() { return _classPrivateFieldGet(_pending, this) === _classPrivateFieldGet(_concurrency, this) && _classPrivateFieldGet(_queue, this).size > 0 || this.isRateLimited && _classPrivateFieldGet(_queue, this).size > 0; } /** The tasks currently being executed. Each task includes its `id`, `priority`, `startTime`, and `timeout` (if set). Returns an array of task info objects. ```js import PQueue from 'p-queue'; const queue = new PQueue({concurrency: 2}); // Add tasks with IDs for better debugging queue.add(() => fetchUser(123), {id: 'user-123'}); queue.add(() => fetchPosts(456), {id: 'posts-456', priority: 1}); // Check what's running console.log(queue.runningTasks); // => [{ // id: 'user-123', // priority: 0, // startTime: 1759253001716, // timeout: undefined // }, { // id: 'posts-456', // priority: 1, // startTime: 1759253001916, // timeout: undefined // }] ``` */ get runningTasks() { // Return fresh array with fresh objects to prevent mutations return [..._classPrivateFieldGet(_runningTasks, this).values()].map(task => ({ ...task })); } } /** Error thrown when a task times out. @example ``` import PQueue, {TimeoutError} from 'p-queue'; const queue = new PQueue({timeout: 1000}); try { await queue.add(() => someTask()); } catch (error) { if (error instanceof TimeoutError) { console.log('Task timed out'); } } ``` */ function _get_doesIntervalAllowAnother(_this) { return _classPrivateFieldGet(_isIntervalIgnored, _this) || _classPrivateFieldGet(_intervalCount, _this) < _classPrivateFieldGet(_intervalCap, _this); } function _get_doesConcurrentAllowAnother(_this2) { return _classPrivateFieldGet(_pending, _this2) < _classPrivateFieldGet(_concurrency, _this2); } function _next() { var _this$pending, _this$pending2; _classPrivateFieldSet(_pending, this, (_this$pending = _classPrivateFieldGet(_pending, this), _this$pending2 = _this$pending--, _this$pending)), _this$pending2; if (_classPrivateFieldGet(_pending, this) === 0) { this.emit('pendingZero'); } _assertClassBrand(_PQueue_brand, this, _tryToStartAnother).call(this); this.emit('next'); } function _onResumeInterval() { _assertClassBrand(_PQueue_brand, this, _onInterval).call(this); // Already schedules update _assertClassBrand(_PQueue_brand, this, _initializeIntervalIfNeeded).call(this); _classPrivateFieldSet(_timeoutId, this, undefined); } function _get_isIntervalPaused(_this3) { const now = Date.now(); if (_classPrivateFieldGet(_intervalId, _this3) === undefined) { const delay = _classPrivateFieldGet(_intervalEnd, _this3) - now; if (delay < 0) { // If the interval has expired while idle, check if we should enforce the interval // from the last task execution. This ensures proper spacing between tasks even // when the queue becomes empty and then new tasks are added. if (_classPrivateFieldGet(_lastExecutionTime, _this3) > 0) { const timeSinceLastExecution = now - _classPrivateFieldGet(_lastExecutionTime, _this3); if (timeSinceLastExecution < _classPrivateFieldGet(_interval, _this3)) { // Not enough time has passed since the last task execution _assertClassBrand(_PQueue_brand, _this3, _createIntervalTimeout).call(_this3, _classPrivateFieldGet(_interval, _this3) - timeSinceLastExecution); return true; } } // Enough time has passed or no previous execution, allow execution _classPrivateFieldSet(_intervalCount, _this3, _classPrivateFieldGet(_carryoverIntervalCount, _this3) ? _classPrivateFieldGet(_pending, _this3) : 0); } else { // Act as the interval is pending _assertClassBrand(_PQueue_brand, _this3, _createIntervalTimeout).call(_this3, delay); return true; } } return false; } function _createIntervalTimeout(delay) { if (_classPrivateFieldGet(_timeoutId, this) !== undefined) { return; } _classPrivateFieldSet(_timeoutId, this, setTimeout(() => { _assertClassBrand(_PQueue_brand, this, _onResumeInterval).call(this); }, delay)); } function _clearIntervalTimer() { if (_classPrivateFieldGet(_intervalId, this)) { clearInterval(_classPrivateFieldGet(_intervalId, this)); _classPrivateFieldSet(_intervalId, this, undefined); } } function _clearTimeoutTimer() { if (_classPrivateFieldGet(_timeoutId, this)) { clearTimeout(_classPrivateFieldGet(_timeoutId, this)); _classPrivateFieldSet(_timeoutId, this, undefined); } } function _tryToStartAnother() { if (_classPrivateFieldGet(_queue, this).size === 0) { // We can clear the interval ("pause") // Because we can redo it later ("resume") _assertClassBrand(_PQueue_brand, this, _clearIntervalTimer).call(this); this.emit('empty'); if (_classPrivateFieldGet(_pending, this) === 0) { // Clear timeout as well when completely idle _assertClassBrand(_PQueue_brand, this, _clearTimeoutTimer).call(this); this.emit('idle'); } return false; } let taskStarted = false; if (!_classPrivateFieldGet(_isPaused, this)) { const canInitializeInterval = !_classPrivateGetter(_PQueue_brand, this, _get_isIntervalPaused); if (_classPrivateGetter(_PQueue_brand, this, _get_doesIntervalAllowAnother) && _classPrivateGetter(_PQueue_brand, this, _get_doesConcurrentAllowAnother)) { const job = _classPrivateFieldGet(_queue, this).dequeue(); // Increment interval count immediately to prevent race conditions if (!_classPrivateFieldGet(_isIntervalIgnored, this)) { var _this$intervalCount, _this$intervalCount2; _classPrivateFieldSet(_intervalCount, this, (_this$intervalCount = _classPrivateFieldGet(_intervalCount, this), _this$intervalCount2 = _this$intervalCount++, _this$intervalCount)), _this$intervalCount2; _assertClassBrand(_PQueue_brand, this, _scheduleRateLimitUpdate).call(this); } this.emit('active'); _classPrivateFieldSet(_lastExecutionTime, this, Date.now()); job(); if (canInitializeInterval) { _assertClassBrand(_PQueue_brand, this, _initializeIntervalIfNeeded).call(this); } taskStarted = true; } } return taskStarted; } function _initializeIntervalIfNeeded() { if (_classPrivateFieldGet(_isIntervalIgnored, this) || _classPrivateFieldGet(_intervalId, this) !== undefined) { return; } _classPrivateFieldSet(_intervalId, this, setInterval(() => { _assertClassBrand(_PQueue_brand, this, _onInterval).call(this); }, _classPrivateFieldGet(_interval, this))); _classPrivateFieldSet(_intervalEnd, this, Date.now() + _classPrivateFieldGet(_interval, this)); } function _onInterval() { if (_classPrivateFieldGet(_intervalCount, this) === 0 && _classPrivateFieldGet(_pending, this) === 0 && _classPrivateFieldGet(_intervalId, this)) { _assertClassBrand(_PQueue_brand, this, _clearIntervalTimer).call(this); } _classPrivateFieldSet(_intervalCount, this, _classPrivateFieldGet(_carryoverIntervalCount, this) ? _classPrivateFieldGet(_pending, this) : 0); _assertClassBrand(_PQueue_brand, this, _processQueue).call(this); _assertClassBrand(_PQueue_brand, this, _scheduleRateLimitUpdate).call(this); } /** Executes all queued functions until it reaches the limit. */ function _processQueue() { // eslint-disable-next-line no-empty while (_assertClassBrand(_PQueue_brand, this, _tryToStartAnother).call(this)) {} } async function _throwOnAbort(signal) { return new Promise((_resolve, reject) => { signal.addEventListener('abort', () => { reject(signal.reason); }, { once: true }); }); } async function _onEvent(event, filter) { return new Promise(resolve => { const listener = () => { if (filter && !filter()) { return; } this.off(event, listener); resolve(); }; this.on(event, listener); }); } function _setupRateLimitTracking() { // Only schedule updates when rate limiting is enabled if (_classPrivateFieldGet(_isIntervalIgnored, this)) { return; } // Wire up to lifecycle events that affect rate limit state // Only 'add' and 'next' can actually change rate limit state this.on('add', () => { if (_classPrivateFieldGet(_queue, this).size > 0) { _assertClassBrand(_PQueue_brand, this, _scheduleRateLimitUpdate).call(this); } }); this.on('next', () => { _assertClassBrand(_PQueue_brand, this, _scheduleRateLimitUpdate).call(this); }); } function _scheduleRateLimitUpdate() { // Skip if rate limiting is not enabled or already scheduled if (_classPrivateFieldGet(_isIntervalIgnored, this) || _classPrivateFieldGet(_rateLimitFlushScheduled, this)) { return; } _classPrivateFieldSet(_rateLimitFlushScheduled, this, true); queueMicrotask(() => { _classPrivateFieldSet(_rateLimitFlushScheduled, this, false); _assertClassBrand(_PQueue_brand, this, _updateRateLimitState).call(this); }); } function _updateRateLimitState() { const previous = _classPrivateFieldGet(_rateLimitedInInterval, this); const shouldBeRateLimited = !_classPrivateFieldGet(_isIntervalIgnored, this) && _classPrivateFieldGet(_intervalCount, this) >= _classPrivateFieldGet(_intervalCap, this) && _classPrivateFieldGet(_queue, this).size > 0; if (shouldBeRateLimited !== previous) { _classPrivateFieldSet(_rateLimitedInInterval, this, shouldBeRateLimited); this.emit(shouldBeRateLimited ? 'rateLimit' : 'rateLimitCleared'); } } export { TimeoutError } from "p-timeout-compat";