p-queue-compat
Version:
Compatible version of p-queue
629 lines (626 loc) • 28.8 kB
JavaScript
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";