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