@tanstack/pacer 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,9 @@
1
1
  import { AnyAsyncFunction } from './types.js';
2
2
  import { QueuePosition } from './queuer.js';
3
- export interface AsyncQueuerOptions<TValue> {
3
+ export type AsyncQueuerFn = AnyAsyncFunction & {
4
+ priority?: number;
5
+ };
6
+ export interface AsyncQueuerOptions<TFn extends AsyncQueuerFn> {
4
7
  /**
5
8
  * Default position to add items to the queuer
6
9
  * @default 'back'
@@ -11,7 +14,7 @@ export interface AsyncQueuerOptions<TValue> {
11
14
  * Can be a number or a function that returns a number.
12
15
  * @default 1
13
16
  */
14
- concurrency?: number | ((queuer: AsyncQueuer<TValue>) => number);
17
+ concurrency?: number | ((queuer: AsyncQueuer<TFn>) => number);
15
18
  /**
16
19
  * Maximum time in milliseconds that an item can stay in the queue
17
20
  * If not provided, items will never expire
@@ -21,7 +24,7 @@ export interface AsyncQueuerOptions<TValue> {
21
24
  * Function to determine if an item has expired
22
25
  * If provided, this overrides the expirationDuration behavior
23
26
  */
24
- getIsExpired?: (item: () => Promise<TValue>, addedAt: number) => boolean;
27
+ getIsExpired?: (item: TFn, addedAt: number) => boolean;
25
28
  /**
26
29
  * Default position to get items from during processing
27
30
  * @default 'front'
@@ -32,47 +35,67 @@ export interface AsyncQueuerOptions<TValue> {
32
35
  * Higher priority items will be processed first
33
36
  * If not provided, will use static priority values attached to tasks
34
37
  */
35
- getPriority?: (item: () => Promise<TValue>) => number;
38
+ getPriority?: (item: TFn) => number;
36
39
  /**
37
40
  * Initial items to populate the queuer with
38
41
  */
39
- initialItems?: Array<(() => Promise<TValue>) & {
42
+ initialItems?: Array<TFn & {
40
43
  priority?: number;
41
44
  }>;
42
45
  /**
43
46
  * Maximum number of items allowed in the queuer
44
47
  */
45
48
  maxSize?: number;
49
+ /**
50
+ * Optional error handler for when a task throws.
51
+ * If provided, the handler will be called with the error and queuer instance.
52
+ * This can be used alongside throwOnError - the handler will be called before any error is thrown.
53
+ */
54
+ onError?: (error: unknown, queuer: AsyncQueuer<TFn>) => void;
55
+ /**
56
+ * Callback fired whenever an item expires in the queuer
57
+ */
58
+ onExpire?: (item: TFn, queuer: AsyncQueuer<TFn>) => void;
46
59
  /**
47
60
  * Callback fired whenever an item is removed from the queuer
48
61
  */
49
- onGetNextItem?: (item: () => Promise<TValue>, queuer: AsyncQueuer<TValue>) => void;
62
+ onGetNextItem?: (item: TFn, queuer: AsyncQueuer<TFn>) => void;
50
63
  /**
51
64
  * Callback fired whenever the queuer's running state changes
52
65
  */
53
- onIsRunningChange?: (queuer: AsyncQueuer<TValue>) => void;
66
+ onIsRunningChange?: (queuer: AsyncQueuer<TFn>) => void;
54
67
  /**
55
68
  * Callback fired whenever an item is added or removed from the queuer
56
69
  */
57
- onItemsChange?: (queuer: AsyncQueuer<TValue>) => void;
70
+ onItemsChange?: (queuer: AsyncQueuer<TFn>) => void;
58
71
  /**
59
72
  * Callback fired whenever an item is rejected from being added to the queuer
60
73
  */
61
- onReject?: (item: () => Promise<TValue>, queuer: AsyncQueuer<TValue>) => void;
74
+ onReject?: (item: TFn, queuer: AsyncQueuer<TFn>) => void;
62
75
  /**
63
- * Callback fired whenever an item expires in the queuer
76
+ * Optional callback to call when a task is settled
64
77
  */
65
- onExpire?: (item: () => Promise<TValue>, queuer: AsyncQueuer<TValue>) => void;
78
+ onSettled?: (queuer: AsyncQueuer<TFn>) => void;
79
+ /**
80
+ * Optional callback to call when a task succeeds
81
+ */
82
+ onSuccess?: (result: TFn, queuer: AsyncQueuer<TFn>) => void;
66
83
  /**
67
84
  * Whether the queuer should start processing tasks immediately or not.
68
85
  */
69
86
  started?: boolean;
87
+ /**
88
+ * Whether to throw errors when they occur.
89
+ * Defaults to true if no onError handler is provided, false if an onError handler is provided.
90
+ * Can be explicitly set to override these defaults.
91
+ */
92
+ throwOnError?: boolean;
70
93
  /**
71
94
  * Time in milliseconds to wait between processing items.
72
95
  * Can be a number or a function that returns a number.
73
96
  * @default 0
74
97
  */
75
- wait?: number | ((queuer: AsyncQueuer<TValue>) => number);
98
+ wait?: number | ((queuer: AsyncQueuer<TFn>) => number);
76
99
  }
77
100
  /**
78
101
  * A flexible asynchronous queue that processes tasks with configurable concurrency control.
@@ -89,44 +112,51 @@ export interface AsyncQueuerOptions<TValue> {
89
112
  * Tasks are processed concurrently up to the configured concurrency limit. When a task completes,
90
113
  * the next pending task is processed if below the concurrency limit.
91
114
  *
115
+ * Error Handling:
116
+ * - If an `onError` handler is provided, it will be called with the error and queuer instance
117
+ * - If `throwOnError` is true (default when no onError handler is provided), the error will be thrown
118
+ * - If `throwOnError` is false (default when onError handler is provided), the error will be swallowed
119
+ * - Both onError and throwOnError can be used together - the handler will be called before any error is thrown
120
+ * - The error state can be checked using the underlying AsyncQueuer instance
121
+ *
92
122
  * @example
93
123
  * ```ts
94
- * const asyncQueuer = new AsyncQueuer<string>({ concurrency: 2 });
124
+ * const asyncQueuer = new AsyncQueuer<string>({
125
+ * concurrency: 2,
126
+ * onSuccess: (result) => {
127
+ * console.log(result); // 'Hello'
128
+ * }
129
+ * });
95
130
  *
96
131
  * asyncQueuer.addItem(async () => {
97
132
  * return 'Hello';
98
133
  * });
99
134
  *
100
135
  * asyncQueuer.start();
101
- *
102
- * asyncQueuer.onSuccess((result) => {
103
- * console.log(result); // 'Hello'
104
- * });
105
136
  * ```
106
137
  */
107
- export declare class AsyncQueuer<TValue> {
138
+ export declare class AsyncQueuer<TFn extends AsyncQueuerFn> {
108
139
  private _options;
109
140
  private _activeItems;
110
- private _executionCount;
141
+ private _successCount;
142
+ private _errorCount;
143
+ private _settledCount;
111
144
  private _rejectionCount;
112
145
  private _expirationCount;
113
146
  private _items;
114
147
  private _itemTimestamps;
115
- private _onErrorCallbacks;
116
- private _onSettledCallbacks;
117
- private _onSuccessCallbacks;
118
148
  private _pendingTick;
119
149
  private _running;
120
- constructor(initialOptions?: AsyncQueuerOptions<TValue>);
150
+ constructor(initialOptions?: AsyncQueuerOptions<TFn>);
121
151
  /**
122
152
  * Updates the queuer options
123
153
  * Returns the new options state
124
154
  */
125
- setOptions(newOptions: Partial<AsyncQueuerOptions<TValue>>): void;
155
+ setOptions(newOptions: Partial<AsyncQueuerOptions<TFn>>): void;
126
156
  /**
127
157
  * Returns the current queuer options
128
158
  */
129
- getOptions(): Required<AsyncQueuerOptions<TValue>>;
159
+ getOptions(): AsyncQueuerOptions<TFn>;
130
160
  /**
131
161
  * Returns the current wait time between processing items
132
162
  */
@@ -162,17 +192,15 @@ export declare class AsyncQueuer<TValue> {
162
192
  /**
163
193
  * Adds a task to the queuer
164
194
  */
165
- addItem(fn: AnyAsyncFunction & {
166
- priority?: number;
167
- }, position?: QueuePosition, runOnItemsChange?: boolean): Promise<TValue>;
195
+ addItem(fn: TFn, position?: QueuePosition, runOnItemsChange?: boolean): void;
168
196
  /**
169
197
  * Removes and returns an item from the queuer
170
198
  */
171
- getNextItem(position?: QueuePosition): (() => Promise<TValue>) | undefined;
199
+ getNextItem(position?: QueuePosition): TFn | undefined;
172
200
  /**
173
201
  * Returns an item without removing it
174
202
  */
175
- getPeek(position?: QueuePosition): (() => Promise<TValue>) | undefined;
203
+ getPeek(position?: QueuePosition): TFn | undefined;
176
204
  /**
177
205
  * Returns true if the queuer is empty
178
206
  */
@@ -188,19 +216,27 @@ export declare class AsyncQueuer<TValue> {
188
216
  /**
189
217
  * Returns a copy of all items in the queuer
190
218
  */
191
- getAllItems(): Array<() => Promise<TValue>>;
219
+ getAllItems(): Array<TFn>;
192
220
  /**
193
221
  * Returns the active items
194
222
  */
195
- getActiveItems(): Array<() => Promise<TValue>>;
223
+ getActiveItems(): Array<TFn>;
196
224
  /**
197
225
  * Returns the pending items
198
226
  */
199
- getPendingItems(): Array<() => Promise<TValue>>;
227
+ getPendingItems(): Array<TFn>;
228
+ /**
229
+ * Returns the number of items that have been successfully processed
230
+ */
231
+ getSuccessCount(): number;
200
232
  /**
201
- * Returns the number of items that have been removed from the queuer
233
+ * Returns the number of items that have failed processing
202
234
  */
203
- getExecutionCount(): number;
235
+ getErrorCount(): number;
236
+ /**
237
+ * Returns the number of items that have completed processing (success or error)
238
+ */
239
+ getSettledCount(): number;
204
240
  /**
205
241
  * Returns the number of items that have been rejected from the queuer
206
242
  */
@@ -213,18 +249,6 @@ export declare class AsyncQueuer<TValue> {
213
249
  * Returns true if the queuer is running but has no items to process
214
250
  */
215
251
  getIsIdle(): boolean;
216
- /**
217
- * Adds a callback to be called when a task succeeds
218
- */
219
- onSuccess(cb: (result: TValue) => void): () => void;
220
- /**
221
- * Adds a callback to be called when a task errors
222
- */
223
- onError(cb: (error: Error) => void): () => void;
224
- /**
225
- * Adds a callback to be called when a task is settled
226
- */
227
- onSettled(cb: (result: TValue | Error) => void): () => void;
228
252
  /**
229
253
  * Returns the number of items that have expired from the queuer
230
254
  */
@@ -234,6 +258,13 @@ export declare class AsyncQueuer<TValue> {
234
258
  * Creates a new AsyncQueuer instance with the given options and returns a bound addItem function.
235
259
  * The queuer is automatically started and ready to process items.
236
260
  *
261
+ * Error Handling:
262
+ * - If an `onError` handler is provided, it will be called with the error and queuer instance
263
+ * - If `throwOnError` is true (default when no onError handler is provided), the error will be thrown
264
+ * - If `throwOnError` is false (default when onError handler is provided), the error will be swallowed
265
+ * - Both onError and throwOnError can be used together - the handler will be called before any error is thrown
266
+ * - The error state can be checked using the underlying AsyncQueuer instance
267
+ *
237
268
  * @example
238
269
  * ```ts
239
270
  * const enqueue = asyncQueue<string>();
@@ -247,6 +278,4 @@ export declare class AsyncQueuer<TValue> {
247
278
  * @param options - Configuration options for the AsyncQueuer
248
279
  * @returns A bound addItem function that can be used to add tasks to the queuer
249
280
  */
250
- export declare function asyncQueue<TValue>(options: AsyncQueuerOptions<TValue>): (fn: AnyAsyncFunction & {
251
- priority?: number;
252
- }, position?: QueuePosition, runOnItemsChange?: boolean) => Promise<TValue>;
281
+ export declare function asyncQueue<TFn extends AsyncQueuerFn>(options: AsyncQueuerOptions<TFn>): (fn: TFn, position?: QueuePosition, runOnItemsChange?: boolean) => void;
@@ -8,32 +8,25 @@ const defaultOptions = {
8
8
  getPriority: (item) => (item == null ? void 0 : item.priority) ?? 0,
9
9
  initialItems: [],
10
10
  maxSize: Infinity,
11
- onGetNextItem: () => {
12
- },
13
- onIsRunningChange: () => {
14
- },
15
- onItemsChange: () => {
16
- },
17
- onReject: () => {
18
- },
19
- onExpire: () => {
20
- },
21
11
  started: true,
22
12
  wait: 0
23
13
  };
24
14
  class AsyncQueuer {
25
15
  constructor(initialOptions = defaultOptions) {
26
16
  this._activeItems = /* @__PURE__ */ new Set();
27
- this._executionCount = 0;
17
+ this._successCount = 0;
18
+ this._errorCount = 0;
19
+ this._settledCount = 0;
28
20
  this._rejectionCount = 0;
29
21
  this._expirationCount = 0;
30
22
  this._items = [];
31
23
  this._itemTimestamps = [];
32
- this._onErrorCallbacks = [];
33
- this._onSettledCallbacks = [];
34
- this._onSuccessCallbacks = [];
35
24
  this._pendingTick = false;
36
- this._options = { ...defaultOptions, ...initialOptions };
25
+ this._options = {
26
+ ...defaultOptions,
27
+ ...initialOptions,
28
+ throwOnError: initialOptions.throwOnError ?? !initialOptions.onError
29
+ };
37
30
  this._running = this._options.started;
38
31
  for (let i = 0; i < this._options.initialItems.length; i++) {
39
32
  const item = this._options.initialItems[i];
@@ -70,6 +63,7 @@ class AsyncQueuer {
70
63
  * Processes items in the queuer
71
64
  */
72
65
  tick() {
66
+ var _a, _b;
73
67
  if (!this._running) {
74
68
  this._pendingTick = false;
75
69
  return;
@@ -81,26 +75,28 @@ class AsyncQueuer {
81
75
  break;
82
76
  }
83
77
  this._activeItems.add(nextFn);
84
- this._options.onItemsChange(this);
78
+ (_b = (_a = this._options).onItemsChange) == null ? void 0 : _b.call(_a, this);
85
79
  (async () => {
86
- let success = false;
80
+ var _a2, _b2, _c, _d, _e, _f, _g, _h;
87
81
  let res;
88
- let error;
89
82
  try {
90
83
  res = await nextFn();
91
- success = true;
92
- } catch (e) {
93
- error = e;
84
+ this._successCount++;
85
+ (_b2 = (_a2 = this._options).onSuccess) == null ? void 0 : _b2.call(_a2, res, this);
86
+ } catch (error) {
87
+ this._errorCount++;
88
+ (_d = (_c = this._options).onError) == null ? void 0 : _d.call(_c, error, this);
89
+ if (this._options.throwOnError) {
90
+ throw error;
91
+ } else {
92
+ console.error(error);
93
+ }
94
94
  } finally {
95
+ this._settledCount++;
95
96
  this._activeItems.delete(nextFn);
96
- this._options.onItemsChange(this);
97
- }
98
- if (success) {
99
- this._onSuccessCallbacks.forEach((cb) => cb(res));
100
- } else {
101
- this._onErrorCallbacks.forEach((cb) => cb(error));
97
+ (_f = (_e = this._options).onItemsChange) == null ? void 0 : _f.call(_e, this);
98
+ (_h = (_g = this._options).onSettled) == null ? void 0 : _h.call(_g, this);
102
99
  }
103
- this._onSettledCallbacks.forEach((cb) => cb(success ? res : error));
104
100
  const wait = this.getWait();
105
101
  if (wait > 0) {
106
102
  setTimeout(() => this.tick(), wait);
@@ -115,6 +111,7 @@ class AsyncQueuer {
115
111
  * Checks for and removes expired items from the queuer
116
112
  */
117
113
  checkExpiredItems() {
114
+ var _a, _b, _c, _d;
118
115
  if (this._options.expirationDuration === Infinity && this._options.getIsExpired === defaultOptions.getIsExpired)
119
116
  return;
120
117
  const now = Date.now();
@@ -137,22 +134,23 @@ class AsyncQueuer {
137
134
  this._items.splice(index, 1);
138
135
  this._itemTimestamps.splice(index, 1);
139
136
  this._expirationCount++;
140
- this._options.onExpire(expiredItem, this);
137
+ (_b = (_a = this._options).onExpire) == null ? void 0 : _b.call(_a, expiredItem, this);
141
138
  }
142
139
  if (expiredIndices.length > 0) {
143
- this._options.onItemsChange(this);
140
+ (_d = (_c = this._options).onItemsChange) == null ? void 0 : _d.call(_c, this);
144
141
  }
145
142
  }
146
143
  /**
147
144
  * Starts the queuer and processes items
148
145
  */
149
146
  start() {
147
+ var _a, _b;
150
148
  this._running = true;
151
149
  if (!this._pendingTick && !this.getIsEmpty()) {
152
150
  this._pendingTick = true;
153
151
  this.tick();
154
152
  }
155
- this._options.onIsRunningChange(this);
153
+ (_b = (_a = this._options).onIsRunningChange) == null ? void 0 : _b.call(_a, this);
156
154
  return new Promise((resolve) => {
157
155
  const checkIdle = () => {
158
156
  if (this.getIsIdle()) {
@@ -168,23 +166,27 @@ class AsyncQueuer {
168
166
  * Stops the queuer from processing items
169
167
  */
170
168
  stop() {
169
+ var _a, _b;
171
170
  this._running = false;
172
171
  this._pendingTick = false;
173
- this._options.onIsRunningChange(this);
172
+ (_b = (_a = this._options).onIsRunningChange) == null ? void 0 : _b.call(_a, this);
174
173
  }
175
174
  /**
176
175
  * Removes all items from the queuer
177
176
  */
178
177
  clear() {
178
+ var _a, _b;
179
179
  this._items = [];
180
- this._options.onItemsChange(this);
180
+ (_b = (_a = this._options).onItemsChange) == null ? void 0 : _b.call(_a, this);
181
181
  }
182
182
  /**
183
183
  * Resets the queuer to its initial state
184
184
  */
185
185
  reset(withInitialItems) {
186
186
  this.clear();
187
- this._executionCount = 0;
187
+ this._successCount = 0;
188
+ this._errorCount = 0;
189
+ this._settledCount = 0;
188
190
  if (withInitialItems) {
189
191
  this._items = [...this._options.initialItems];
190
192
  }
@@ -194,60 +196,47 @@ class AsyncQueuer {
194
196
  * Adds a task to the queuer
195
197
  */
196
198
  addItem(fn, position = this._options.addItemsTo, runOnItemsChange = true) {
199
+ var _a, _b, _c, _d;
197
200
  if (this.getIsFull()) {
198
201
  this._rejectionCount++;
199
- this._options.onReject(fn, this);
200
- return Promise.reject(new Error("Queuer is full"));
202
+ (_b = (_a = this._options).onReject) == null ? void 0 : _b.call(_a, fn, this);
203
+ return;
201
204
  }
202
- return new Promise((resolve, reject) => {
203
- const task = Object.assign(
204
- async () => {
205
- try {
206
- const result = await fn();
207
- resolve(result);
208
- return result;
209
- } catch (error) {
210
- reject(error);
211
- throw error;
212
- }
213
- },
214
- { priority: fn.priority ?? void 0 }
215
- );
216
- const priority = this._options.getPriority !== defaultOptions.getPriority ? this._options.getPriority(task) : task.priority;
217
- if (priority !== void 0) {
218
- const insertIndex = this._items.findIndex((existing) => {
219
- const existingPriority = this._options.getPriority !== defaultOptions.getPriority ? this._options.getPriority(existing) : existing.priority;
220
- return existingPriority > priority;
221
- });
222
- if (insertIndex === -1) {
223
- this._items.push(task);
224
- this._itemTimestamps.push(Date.now());
225
- } else {
226
- this._items.splice(insertIndex, 0, task);
227
- this._itemTimestamps.splice(insertIndex, 0, Date.now());
228
- }
205
+ const priority = this._options.getPriority !== defaultOptions.getPriority ? this._options.getPriority(fn) : fn.priority;
206
+ if (priority !== void 0) {
207
+ const insertIndex = this._items.findIndex((existing) => {
208
+ const existingPriority = this._options.getPriority !== defaultOptions.getPriority ? this._options.getPriority(existing) : existing.priority;
209
+ return existingPriority > priority;
210
+ });
211
+ if (insertIndex === -1) {
212
+ this._items.push(fn);
213
+ this._itemTimestamps.push(Date.now());
229
214
  } else {
230
- if (position === "front") {
231
- this._items.unshift(task);
232
- this._itemTimestamps.unshift(Date.now());
233
- } else {
234
- this._items.push(task);
235
- this._itemTimestamps.push(Date.now());
236
- }
237
- }
238
- if (runOnItemsChange) {
239
- this._options.onItemsChange(this);
215
+ this._items.splice(insertIndex, 0, fn);
216
+ this._itemTimestamps.splice(insertIndex, 0, Date.now());
240
217
  }
241
- if (this._running && !this._pendingTick) {
242
- this._pendingTick = true;
243
- this.tick();
218
+ } else {
219
+ if (position === "front") {
220
+ this._items.unshift(fn);
221
+ this._itemTimestamps.unshift(Date.now());
222
+ } else {
223
+ this._items.push(fn);
224
+ this._itemTimestamps.push(Date.now());
244
225
  }
245
- });
226
+ }
227
+ if (runOnItemsChange) {
228
+ (_d = (_c = this._options).onItemsChange) == null ? void 0 : _d.call(_c, this);
229
+ }
230
+ if (this._running && !this._pendingTick) {
231
+ this._pendingTick = true;
232
+ this.tick();
233
+ }
246
234
  }
247
235
  /**
248
236
  * Removes and returns an item from the queuer
249
237
  */
250
238
  getNextItem(position = this._options.getItemsFrom) {
239
+ var _a, _b, _c, _d;
251
240
  let item;
252
241
  if (position === "front") {
253
242
  item = this._items.shift();
@@ -257,9 +246,8 @@ class AsyncQueuer {
257
246
  this._itemTimestamps.pop();
258
247
  }
259
248
  if (item !== void 0) {
260
- this._executionCount++;
261
- this._options.onItemsChange(this);
262
- this._options.onGetNextItem(item, this);
249
+ (_b = (_a = this._options).onItemsChange) == null ? void 0 : _b.call(_a, this);
250
+ (_d = (_c = this._options).onGetNextItem) == null ? void 0 : _d.call(_c, item, this);
263
251
  }
264
252
  return item;
265
253
  }
@@ -309,10 +297,22 @@ class AsyncQueuer {
309
297
  return [...this._items];
310
298
  }
311
299
  /**
312
- * Returns the number of items that have been removed from the queuer
300
+ * Returns the number of items that have been successfully processed
301
+ */
302
+ getSuccessCount() {
303
+ return this._successCount;
304
+ }
305
+ /**
306
+ * Returns the number of items that have failed processing
313
307
  */
314
- getExecutionCount() {
315
- return this._executionCount;
308
+ getErrorCount() {
309
+ return this._errorCount;
310
+ }
311
+ /**
312
+ * Returns the number of items that have completed processing (success or error)
313
+ */
314
+ getSettledCount() {
315
+ return this._settledCount;
316
316
  }
317
317
  /**
318
318
  * Returns the number of items that have been rejected from the queuer
@@ -332,37 +332,6 @@ class AsyncQueuer {
332
332
  getIsIdle() {
333
333
  return this._running && this.getIsEmpty() && this._activeItems.size === 0;
334
334
  }
335
- /**
336
- * Adds a callback to be called when a task succeeds
337
- */
338
- onSuccess(cb) {
339
- this._onSuccessCallbacks.push(cb);
340
- return () => {
341
- this._onSuccessCallbacks = this._onSuccessCallbacks.filter(
342
- (d) => d !== cb
343
- );
344
- };
345
- }
346
- /**
347
- * Adds a callback to be called when a task errors
348
- */
349
- onError(cb) {
350
- this._onErrorCallbacks.push(cb);
351
- return () => {
352
- this._onErrorCallbacks = this._onErrorCallbacks.filter((d) => d !== cb);
353
- };
354
- }
355
- /**
356
- * Adds a callback to be called when a task is settled
357
- */
358
- onSettled(cb) {
359
- this._onSettledCallbacks.push(cb);
360
- return () => {
361
- this._onSettledCallbacks = this._onSettledCallbacks.filter(
362
- (d) => d !== cb
363
- );
364
- };
365
- }
366
335
  /**
367
336
  * Returns the number of items that have expired from the queuer
368
337
  */