@tanstack/pacer 0.1.0 → 0.2.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.
- package/dist/cjs/async-debouncer.cjs +60 -44
- package/dist/cjs/async-debouncer.cjs.map +1 -1
- package/dist/cjs/async-debouncer.d.cts +37 -24
- package/dist/cjs/async-queuer.cjs +149 -125
- package/dist/cjs/async-queuer.cjs.map +1 -1
- package/dist/cjs/async-queuer.d.cts +65 -48
- package/dist/cjs/async-rate-limiter.cjs +63 -46
- package/dist/cjs/async-rate-limiter.cjs.map +1 -1
- package/dist/cjs/async-rate-limiter.d.cts +39 -27
- package/dist/cjs/async-throttler.cjs +70 -47
- package/dist/cjs/async-throttler.cjs.map +1 -1
- package/dist/cjs/async-throttler.d.cts +43 -25
- package/dist/cjs/debouncer.cjs +46 -22
- package/dist/cjs/debouncer.cjs.map +1 -1
- package/dist/cjs/debouncer.d.cts +25 -11
- package/dist/cjs/index.cjs +2 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +2 -0
- package/dist/cjs/queuer.cjs +114 -104
- package/dist/cjs/queuer.cjs.map +1 -1
- package/dist/cjs/queuer.d.cts +53 -40
- package/dist/cjs/rate-limiter.cjs +54 -42
- package/dist/cjs/rate-limiter.cjs.map +1 -1
- package/dist/cjs/rate-limiter.d.cts +37 -45
- package/dist/cjs/throttler.cjs +61 -41
- package/dist/cjs/throttler.cjs.map +1 -1
- package/dist/cjs/throttler.d.cts +35 -22
- package/dist/cjs/types.d.cts +12 -0
- package/dist/cjs/utils.cjs +13 -0
- package/dist/cjs/utils.cjs.map +1 -0
- package/dist/cjs/utils.d.cts +1 -0
- package/dist/esm/async-debouncer.d.ts +37 -24
- package/dist/esm/async-debouncer.js +60 -44
- package/dist/esm/async-debouncer.js.map +1 -1
- package/dist/esm/async-queuer.d.ts +65 -48
- package/dist/esm/async-queuer.js +149 -125
- package/dist/esm/async-queuer.js.map +1 -1
- package/dist/esm/async-rate-limiter.d.ts +39 -27
- package/dist/esm/async-rate-limiter.js +63 -46
- package/dist/esm/async-rate-limiter.js.map +1 -1
- package/dist/esm/async-throttler.d.ts +43 -25
- package/dist/esm/async-throttler.js +70 -47
- package/dist/esm/async-throttler.js.map +1 -1
- package/dist/esm/debouncer.d.ts +25 -11
- package/dist/esm/debouncer.js +46 -22
- package/dist/esm/debouncer.js.map +1 -1
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/queuer.d.ts +53 -40
- package/dist/esm/queuer.js +114 -104
- package/dist/esm/queuer.js.map +1 -1
- package/dist/esm/rate-limiter.d.ts +37 -45
- package/dist/esm/rate-limiter.js +54 -42
- package/dist/esm/rate-limiter.js.map +1 -1
- package/dist/esm/throttler.d.ts +35 -22
- package/dist/esm/throttler.js +61 -41
- package/dist/esm/throttler.js.map +1 -1
- package/dist/esm/types.d.ts +12 -0
- package/dist/esm/utils.d.ts +1 -0
- package/dist/esm/utils.js +13 -0
- package/dist/esm/utils.js.map +1 -0
- package/package.json +8 -1
- package/src/async-debouncer.ts +90 -62
- package/src/async-queuer.ts +178 -145
- package/src/async-rate-limiter.ts +93 -67
- package/src/async-throttler.ts +98 -63
- package/src/debouncer.ts +71 -35
- package/src/index.ts +2 -0
- package/src/queuer.ts +135 -118
- package/src/rate-limiter.ts +79 -81
- package/src/throttler.ts +87 -61
- package/src/types.ts +17 -0
- package/src/utils.ts +13 -0
package/src/async-queuer.ts
CHANGED
|
@@ -36,10 +36,18 @@ export interface AsyncQueuerOptions<TValue> {
|
|
|
36
36
|
item: () => Promise<TValue>,
|
|
37
37
|
queuer: AsyncQueuer<TValue>,
|
|
38
38
|
) => void
|
|
39
|
+
/**
|
|
40
|
+
* Callback fired whenever the queuer's running state changes
|
|
41
|
+
*/
|
|
42
|
+
onIsRunningChange?: (queuer: AsyncQueuer<TValue>) => void
|
|
39
43
|
/**
|
|
40
44
|
* Callback fired whenever an item is added or removed from the queuer
|
|
41
45
|
*/
|
|
42
|
-
|
|
46
|
+
onItemsChange?: (queuer: AsyncQueuer<TValue>) => void
|
|
47
|
+
/**
|
|
48
|
+
* Callback fired whenever an item is rejected from being added to the queuer
|
|
49
|
+
*/
|
|
50
|
+
onReject?: (item: () => Promise<TValue>, queuer: AsyncQueuer<TValue>) => void
|
|
43
51
|
/**
|
|
44
52
|
* Whether the queuer should start processing tasks immediately
|
|
45
53
|
*/
|
|
@@ -54,23 +62,25 @@ const defaultOptions: Required<AsyncQueuerOptions<any>> = {
|
|
|
54
62
|
addItemsTo: 'back',
|
|
55
63
|
concurrency: 1,
|
|
56
64
|
getItemsFrom: 'front',
|
|
57
|
-
getPriority: (item) => (item as any)
|
|
65
|
+
getPriority: (item) => (item as any)?.priority ?? 0,
|
|
58
66
|
initialItems: [],
|
|
59
67
|
maxSize: Infinity,
|
|
60
68
|
onGetNextItem: () => {},
|
|
61
|
-
|
|
69
|
+
onIsRunningChange: () => {},
|
|
70
|
+
onItemsChange: () => {},
|
|
71
|
+
onReject: () => {},
|
|
62
72
|
started: false,
|
|
63
73
|
wait: 0,
|
|
64
74
|
}
|
|
65
75
|
|
|
66
76
|
/**
|
|
67
|
-
* A flexible asynchronous
|
|
77
|
+
* A flexible asynchronous queue that processes tasks with configurable concurrency control.
|
|
68
78
|
*
|
|
69
79
|
* Features:
|
|
70
|
-
* - Priority
|
|
80
|
+
* - Priority queue support via getPriority option
|
|
71
81
|
* - Configurable concurrency limit
|
|
72
82
|
* - Task success/error/completion callbacks
|
|
73
|
-
* - FIFO (First In First Out) or LIFO (Last In First Out)
|
|
83
|
+
* - FIFO (First In First Out) or LIFO (Last In First Out) queue behavior
|
|
74
84
|
* - Pause/resume task processing
|
|
75
85
|
* - Task cancellation
|
|
76
86
|
*
|
|
@@ -79,38 +89,39 @@ const defaultOptions: Required<AsyncQueuerOptions<any>> = {
|
|
|
79
89
|
*
|
|
80
90
|
* @example
|
|
81
91
|
* ```ts
|
|
82
|
-
* const
|
|
92
|
+
* const asyncQueuer = new AsyncQueuer<string>({ concurrency: 2 });
|
|
83
93
|
*
|
|
84
|
-
*
|
|
94
|
+
* asyncQueuer.addItem(async () => {
|
|
85
95
|
* return 'Hello';
|
|
86
96
|
* });
|
|
87
97
|
*
|
|
88
|
-
*
|
|
98
|
+
* asyncQueuer.start();
|
|
89
99
|
*
|
|
90
|
-
*
|
|
100
|
+
* asyncQueuer.onSuccess((result) => {
|
|
91
101
|
* console.log(result); // 'Hello'
|
|
92
102
|
* });
|
|
93
103
|
* ```
|
|
94
104
|
*/
|
|
95
105
|
export class AsyncQueuer<TValue> {
|
|
96
|
-
|
|
97
|
-
private
|
|
98
|
-
private
|
|
99
|
-
private
|
|
100
|
-
private
|
|
101
|
-
private
|
|
102
|
-
private
|
|
103
|
-
private
|
|
104
|
-
private
|
|
106
|
+
private _options: Required<AsyncQueuerOptions<TValue>>
|
|
107
|
+
private _activeItems: Set<() => Promise<TValue>> = new Set()
|
|
108
|
+
private _executionCount = 0
|
|
109
|
+
private _rejectionCount = 0
|
|
110
|
+
private _items: Array<() => Promise<TValue>> = []
|
|
111
|
+
private _onErrorCallbacks: Array<(error: Error) => void> = []
|
|
112
|
+
private _onSettledCallbacks: Array<(result: TValue | Error) => void> = []
|
|
113
|
+
private _onSuccessCallbacks: Array<(result: TValue) => void> = []
|
|
114
|
+
private _pendingTick = false
|
|
115
|
+
private _running: boolean
|
|
105
116
|
|
|
106
117
|
constructor(initialOptions: AsyncQueuerOptions<TValue> = defaultOptions) {
|
|
107
|
-
this.
|
|
108
|
-
this.
|
|
118
|
+
this._options = { ...defaultOptions, ...initialOptions }
|
|
119
|
+
this._running = this._options.started
|
|
109
120
|
|
|
110
|
-
for (let i = 0; i < this.
|
|
111
|
-
const item = this.
|
|
112
|
-
const isLast = i === this.
|
|
113
|
-
this.addItem(item, this.
|
|
121
|
+
for (let i = 0; i < this._options.initialItems.length; i++) {
|
|
122
|
+
const item = this._options.initialItems[i]!
|
|
123
|
+
const isLast = i === this._options.initialItems.length - 1
|
|
124
|
+
this.addItem(item, this._options.addItemsTo, isLast)
|
|
114
125
|
}
|
|
115
126
|
}
|
|
116
127
|
|
|
@@ -121,29 +132,36 @@ export class AsyncQueuer<TValue> {
|
|
|
121
132
|
setOptions(
|
|
122
133
|
newOptions: Partial<AsyncQueuerOptions<TValue>>,
|
|
123
134
|
): AsyncQueuerOptions<TValue> {
|
|
124
|
-
this.
|
|
125
|
-
return this.
|
|
135
|
+
this._options = { ...this._options, ...newOptions }
|
|
136
|
+
return this._options
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Returns the current queuer options
|
|
141
|
+
*/
|
|
142
|
+
getOptions(): Required<AsyncQueuerOptions<TValue>> {
|
|
143
|
+
return this._options
|
|
126
144
|
}
|
|
127
145
|
|
|
128
146
|
/**
|
|
129
147
|
* Processes items in the queuer
|
|
130
148
|
*/
|
|
131
|
-
|
|
132
|
-
if (!this.
|
|
133
|
-
this.
|
|
149
|
+
private tick() {
|
|
150
|
+
if (!this._running) {
|
|
151
|
+
this._pendingTick = false
|
|
134
152
|
return
|
|
135
153
|
}
|
|
136
154
|
|
|
137
155
|
while (
|
|
138
|
-
this.
|
|
139
|
-
!this.
|
|
156
|
+
this._activeItems.size < this._options.concurrency &&
|
|
157
|
+
!this.getIsEmpty()
|
|
140
158
|
) {
|
|
141
159
|
const nextFn = this.getNextItem()
|
|
142
160
|
if (!nextFn) {
|
|
143
161
|
break
|
|
144
162
|
}
|
|
145
|
-
|
|
146
|
-
this.
|
|
163
|
+
this._activeItems.add(nextFn)
|
|
164
|
+
this._options.onItemsChange(this)
|
|
147
165
|
;(async () => {
|
|
148
166
|
let success = false
|
|
149
167
|
let res!: TValue
|
|
@@ -155,19 +173,19 @@ export class AsyncQueuer<TValue> {
|
|
|
155
173
|
} catch (e) {
|
|
156
174
|
error = e as Error
|
|
157
175
|
} finally {
|
|
158
|
-
this.
|
|
176
|
+
this._activeItems.delete(nextFn)
|
|
177
|
+
this._options.onItemsChange(this)
|
|
159
178
|
}
|
|
160
179
|
|
|
161
|
-
this.activeItems.delete(nextFn)
|
|
162
180
|
if (success) {
|
|
163
|
-
this.
|
|
181
|
+
this._onSuccessCallbacks.forEach((cb) => cb(res))
|
|
164
182
|
} else {
|
|
165
|
-
this.
|
|
183
|
+
this._onErrorCallbacks.forEach((cb) => cb(error!))
|
|
166
184
|
}
|
|
167
|
-
this.
|
|
185
|
+
this._onSettledCallbacks.forEach((cb) => cb(success ? res : error!))
|
|
168
186
|
|
|
169
|
-
if (this.
|
|
170
|
-
setTimeout(() => this.tick(), this.
|
|
187
|
+
if (this._options.wait > 0) {
|
|
188
|
+
setTimeout(() => this.tick(), this._options.wait)
|
|
171
189
|
return
|
|
172
190
|
}
|
|
173
191
|
|
|
@@ -175,7 +193,59 @@ export class AsyncQueuer<TValue> {
|
|
|
175
193
|
})()
|
|
176
194
|
}
|
|
177
195
|
|
|
178
|
-
this.
|
|
196
|
+
this._pendingTick = false
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Starts the queuer and processes items
|
|
201
|
+
*/
|
|
202
|
+
start(): Promise<void> {
|
|
203
|
+
this._running = true
|
|
204
|
+
if (!this._pendingTick && !this.getIsEmpty()) {
|
|
205
|
+
this._pendingTick = true
|
|
206
|
+
this.tick()
|
|
207
|
+
}
|
|
208
|
+
this._options.onIsRunningChange(this)
|
|
209
|
+
|
|
210
|
+
return new Promise<void>((resolve) => {
|
|
211
|
+
const checkIdle = () => {
|
|
212
|
+
if (this.getIsIdle()) {
|
|
213
|
+
resolve()
|
|
214
|
+
} else {
|
|
215
|
+
setTimeout(checkIdle, 100)
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
checkIdle()
|
|
219
|
+
})
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Stops the queuer from processing items
|
|
224
|
+
*/
|
|
225
|
+
stop(): void {
|
|
226
|
+
this._running = false
|
|
227
|
+
this._pendingTick = false
|
|
228
|
+
this._options.onIsRunningChange(this)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Removes all items from the queuer
|
|
233
|
+
*/
|
|
234
|
+
clear(): void {
|
|
235
|
+
this._items = []
|
|
236
|
+
this._options.onItemsChange(this)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Resets the queuer to its initial state
|
|
241
|
+
*/
|
|
242
|
+
reset(withInitialItems?: boolean): void {
|
|
243
|
+
this.clear()
|
|
244
|
+
this._executionCount = 0
|
|
245
|
+
if (withInitialItems) {
|
|
246
|
+
this._items = [...this._options.initialItems]
|
|
247
|
+
}
|
|
248
|
+
this._running = this._options.started
|
|
179
249
|
}
|
|
180
250
|
|
|
181
251
|
/**
|
|
@@ -183,10 +253,12 @@ export class AsyncQueuer<TValue> {
|
|
|
183
253
|
*/
|
|
184
254
|
addItem(
|
|
185
255
|
fn: (() => Promise<TValue>) & { priority?: number },
|
|
186
|
-
position: QueuePosition = this.
|
|
256
|
+
position: QueuePosition = this._options.addItemsTo,
|
|
187
257
|
runOnUpdate: boolean = true,
|
|
188
258
|
): Promise<TValue> {
|
|
189
|
-
if (this.
|
|
259
|
+
if (this.getIsFull()) {
|
|
260
|
+
this._rejectionCount++
|
|
261
|
+
this._options.onReject(fn, this)
|
|
190
262
|
return Promise.reject(new Error('Queuer is full'))
|
|
191
263
|
}
|
|
192
264
|
|
|
@@ -207,40 +279,40 @@ export class AsyncQueuer<TValue> {
|
|
|
207
279
|
|
|
208
280
|
// Get priority either from the function or from getPriority option
|
|
209
281
|
const priority =
|
|
210
|
-
this.
|
|
211
|
-
? this.
|
|
282
|
+
this._options.getPriority !== defaultOptions.getPriority
|
|
283
|
+
? this._options.getPriority(task)
|
|
212
284
|
: task.priority
|
|
213
285
|
|
|
214
286
|
if (priority !== undefined) {
|
|
215
287
|
// Insert based on priority
|
|
216
|
-
const insertIndex = this.
|
|
288
|
+
const insertIndex = this._items.findIndex((existing) => {
|
|
217
289
|
const existingPriority =
|
|
218
|
-
this.
|
|
219
|
-
? this.
|
|
290
|
+
this._options.getPriority !== defaultOptions.getPriority
|
|
291
|
+
? this._options.getPriority(existing)
|
|
220
292
|
: (existing as any).priority
|
|
221
293
|
return existingPriority > priority
|
|
222
294
|
})
|
|
223
295
|
|
|
224
296
|
if (insertIndex === -1) {
|
|
225
|
-
this.
|
|
297
|
+
this._items.push(task)
|
|
226
298
|
} else {
|
|
227
|
-
this.
|
|
299
|
+
this._items.splice(insertIndex, 0, task)
|
|
228
300
|
}
|
|
229
301
|
} else {
|
|
230
302
|
// Default FIFO/LIFO behavior
|
|
231
303
|
if (position === 'front') {
|
|
232
|
-
this.
|
|
304
|
+
this._items.unshift(task)
|
|
233
305
|
} else {
|
|
234
|
-
this.
|
|
306
|
+
this._items.push(task)
|
|
235
307
|
}
|
|
236
308
|
}
|
|
237
309
|
|
|
238
310
|
if (runOnUpdate) {
|
|
239
|
-
this.
|
|
311
|
+
this._options.onItemsChange(this)
|
|
240
312
|
}
|
|
241
313
|
|
|
242
|
-
if (this.
|
|
243
|
-
this.
|
|
314
|
+
if (this._running && !this._pendingTick) {
|
|
315
|
+
this._pendingTick = true
|
|
244
316
|
this.tick()
|
|
245
317
|
}
|
|
246
318
|
})
|
|
@@ -250,20 +322,20 @@ export class AsyncQueuer<TValue> {
|
|
|
250
322
|
* Removes and returns an item from the queuer
|
|
251
323
|
*/
|
|
252
324
|
getNextItem(
|
|
253
|
-
position: QueuePosition = this.
|
|
325
|
+
position: QueuePosition = this._options.getItemsFrom,
|
|
254
326
|
): (() => Promise<TValue>) | undefined {
|
|
255
327
|
let item: (() => Promise<TValue>) | undefined
|
|
256
328
|
|
|
257
329
|
if (position === 'front') {
|
|
258
|
-
item = this.
|
|
330
|
+
item = this._items.shift()
|
|
259
331
|
} else {
|
|
260
|
-
item = this.
|
|
332
|
+
item = this._items.pop()
|
|
261
333
|
}
|
|
262
334
|
|
|
263
335
|
if (item !== undefined) {
|
|
264
|
-
this.
|
|
265
|
-
this.
|
|
266
|
-
this.
|
|
336
|
+
this._executionCount++
|
|
337
|
+
this._options.onItemsChange(this)
|
|
338
|
+
this._options.onGetNextItem(item, this)
|
|
267
339
|
}
|
|
268
340
|
return item
|
|
269
341
|
}
|
|
@@ -271,89 +343,94 @@ export class AsyncQueuer<TValue> {
|
|
|
271
343
|
/**
|
|
272
344
|
* Returns an item without removing it
|
|
273
345
|
*/
|
|
274
|
-
|
|
346
|
+
getPeek(
|
|
347
|
+
position: QueuePosition = 'front',
|
|
348
|
+
): (() => Promise<TValue>) | undefined {
|
|
275
349
|
if (position === 'front') {
|
|
276
|
-
return this.
|
|
350
|
+
return this._items[0]
|
|
277
351
|
}
|
|
278
|
-
return this.
|
|
352
|
+
return this._items[this._items.length - 1]
|
|
279
353
|
}
|
|
280
354
|
|
|
281
355
|
/**
|
|
282
356
|
* Returns true if the queuer is empty
|
|
283
357
|
*/
|
|
284
|
-
|
|
285
|
-
return this.
|
|
358
|
+
getIsEmpty(): boolean {
|
|
359
|
+
return this._items.length === 0
|
|
286
360
|
}
|
|
287
361
|
|
|
288
362
|
/**
|
|
289
363
|
* Returns true if the queuer is full
|
|
290
364
|
*/
|
|
291
|
-
|
|
292
|
-
return this.
|
|
365
|
+
getIsFull(): boolean {
|
|
366
|
+
return this._items.length >= this._options.maxSize
|
|
293
367
|
}
|
|
294
368
|
|
|
295
369
|
/**
|
|
296
370
|
* Returns the current size of the queuer
|
|
297
371
|
*/
|
|
298
|
-
|
|
299
|
-
return this.
|
|
372
|
+
getSize(): number {
|
|
373
|
+
return this._items.length
|
|
300
374
|
}
|
|
301
375
|
|
|
302
376
|
/**
|
|
303
|
-
*
|
|
377
|
+
* Returns a copy of all items in the queuer
|
|
304
378
|
*/
|
|
305
|
-
|
|
306
|
-
this.
|
|
307
|
-
this.options.onUpdate(this)
|
|
379
|
+
getAllItems(): Array<() => Promise<TValue>> {
|
|
380
|
+
return [...this.getActiveItems(), ...this.getPendingItems()]
|
|
308
381
|
}
|
|
309
382
|
|
|
310
383
|
/**
|
|
311
|
-
*
|
|
384
|
+
* Returns the active items
|
|
312
385
|
*/
|
|
313
|
-
|
|
314
|
-
this.
|
|
315
|
-
this.executionCount = 0
|
|
316
|
-
if (withInitialItems) {
|
|
317
|
-
this.items = [...this.options.initialItems]
|
|
318
|
-
}
|
|
319
|
-
this.running = this.options.started
|
|
386
|
+
getActiveItems(): Array<() => Promise<TValue>> {
|
|
387
|
+
return Array.from(this._activeItems)
|
|
320
388
|
}
|
|
321
389
|
|
|
322
390
|
/**
|
|
323
|
-
* Returns
|
|
391
|
+
* Returns the pending items
|
|
324
392
|
*/
|
|
325
|
-
|
|
326
|
-
return [...this.
|
|
393
|
+
getPendingItems(): Array<() => Promise<TValue>> {
|
|
394
|
+
return [...this._items]
|
|
327
395
|
}
|
|
328
396
|
|
|
329
397
|
/**
|
|
330
398
|
* Returns the number of items that have been removed from the queuer
|
|
331
399
|
*/
|
|
332
400
|
getExecutionCount(): number {
|
|
333
|
-
return this.
|
|
401
|
+
return this._executionCount
|
|
334
402
|
}
|
|
335
403
|
|
|
336
404
|
/**
|
|
337
|
-
* Returns the
|
|
405
|
+
* Returns the number of items that have been rejected from the queuer
|
|
338
406
|
*/
|
|
339
|
-
|
|
340
|
-
return
|
|
407
|
+
getRejectionCount(): number {
|
|
408
|
+
return this._rejectionCount
|
|
341
409
|
}
|
|
342
410
|
|
|
343
411
|
/**
|
|
344
|
-
* Returns the
|
|
412
|
+
* Returns true if the queuer is running
|
|
345
413
|
*/
|
|
346
|
-
|
|
347
|
-
return this.
|
|
414
|
+
getIsRunning(): boolean {
|
|
415
|
+
return this._running
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Returns true if the queuer is running but has no items to process
|
|
420
|
+
*/
|
|
421
|
+
getIsIdle(): boolean {
|
|
422
|
+
return this._running && this.getIsEmpty() && this._activeItems.size === 0
|
|
348
423
|
}
|
|
349
424
|
|
|
350
425
|
/**
|
|
351
426
|
* Adds a callback to be called when a task succeeds
|
|
352
427
|
*/
|
|
353
428
|
onSuccess(cb: (result: TValue) => void) {
|
|
354
|
-
this.
|
|
429
|
+
this._onSuccessCallbacks.push(cb)
|
|
355
430
|
return () => {
|
|
356
|
-
this.
|
|
431
|
+
this._onSuccessCallbacks = this._onSuccessCallbacks.filter(
|
|
432
|
+
(d) => d !== cb,
|
|
433
|
+
)
|
|
357
434
|
}
|
|
358
435
|
}
|
|
359
436
|
|
|
@@ -361,9 +438,9 @@ export class AsyncQueuer<TValue> {
|
|
|
361
438
|
* Adds a callback to be called when a task errors
|
|
362
439
|
*/
|
|
363
440
|
onError(cb: (error: Error) => void) {
|
|
364
|
-
this.
|
|
441
|
+
this._onErrorCallbacks.push(cb)
|
|
365
442
|
return () => {
|
|
366
|
-
this.
|
|
443
|
+
this._onErrorCallbacks = this._onErrorCallbacks.filter((d) => d !== cb)
|
|
367
444
|
}
|
|
368
445
|
}
|
|
369
446
|
|
|
@@ -371,56 +448,12 @@ export class AsyncQueuer<TValue> {
|
|
|
371
448
|
* Adds a callback to be called when a task is settled
|
|
372
449
|
*/
|
|
373
450
|
onSettled(cb: (result: TValue | Error) => void) {
|
|
374
|
-
this.
|
|
451
|
+
this._onSettledCallbacks.push(cb)
|
|
375
452
|
return () => {
|
|
376
|
-
this.
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
/**
|
|
381
|
-
* Starts the queuer and processes items
|
|
382
|
-
*/
|
|
383
|
-
start(): Promise<void> {
|
|
384
|
-
this.running = true
|
|
385
|
-
if (!this.pendingTick && !this.isEmpty()) {
|
|
386
|
-
this.pendingTick = true
|
|
387
|
-
this.tick()
|
|
453
|
+
this._onSettledCallbacks = this._onSettledCallbacks.filter(
|
|
454
|
+
(d) => d !== cb,
|
|
455
|
+
)
|
|
388
456
|
}
|
|
389
|
-
this.options.onUpdate(this)
|
|
390
|
-
|
|
391
|
-
return new Promise<void>((resolve) => {
|
|
392
|
-
const checkIdle = () => {
|
|
393
|
-
if (this.isIdle()) {
|
|
394
|
-
resolve()
|
|
395
|
-
} else {
|
|
396
|
-
setTimeout(checkIdle, 100)
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
checkIdle()
|
|
400
|
-
})
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
/**
|
|
404
|
-
* Stops the queuer from processing items
|
|
405
|
-
*/
|
|
406
|
-
stop(): void {
|
|
407
|
-
this.running = false
|
|
408
|
-
this.pendingTick = false
|
|
409
|
-
this.options.onUpdate(this)
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
/**
|
|
413
|
-
* Returns true if the queuer is running
|
|
414
|
-
*/
|
|
415
|
-
isRunning(): boolean {
|
|
416
|
-
return this.running
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
/**
|
|
420
|
-
* Returns true if the queuer is running but has no items to process
|
|
421
|
-
*/
|
|
422
|
-
isIdle(): boolean {
|
|
423
|
-
return this.running && this.isEmpty() && this.activeItems.size === 0
|
|
424
457
|
}
|
|
425
458
|
}
|
|
426
459
|
|