@@ -8,8 +8,6 @@ type Task<TaskResultType> =
8
8
| ( ( options : TaskOptions ) => PromiseLike < TaskResultType > )
9
9
| ( ( options : TaskOptions ) => TaskResultType ) ;
10
10
11
- const timeoutError = new TimeoutError ( ) ;
12
-
13
11
/**
14
12
The error thrown by `queue.add()` when a job is aborted before it is run. See `signal`.
15
13
*/
@@ -41,7 +39,7 @@ export default class PQueue<QueueType extends Queue<RunFunction, EnqueueOptionsT
41
39
42
40
readonly #queueClass: new ( ) => QueueType ;
43
41
44
- #pendingCount = 0 ;
42
+ #pending = 0 ;
45
43
46
44
// The `!` is needed because of https://github.com/microsoft/TypeScript/issues/32194
47
45
#concurrency! : number ;
@@ -96,23 +94,15 @@ export default class PQueue<QueueType extends Queue<RunFunction, EnqueueOptionsT
96
94
}
97
95
98
96
get #doesConcurrentAllowAnother( ) : boolean {
99
- return this . #pendingCount < this . #concurrency;
97
+ return this . #pending < this . #concurrency;
100
98
}
101
99
102
100
#next( ) : void {
103
- this . #pendingCount -- ;
101
+ this . #pending -- ;
104
102
this . #tryToStartAnother( ) ;
105
103
this . emit ( 'next' ) ;
106
104
}
107
105
108
- #emitEvents( ) : void {
109
- this . emit ( 'empty' ) ;
110
-
111
- if ( this . #pendingCount === 0 ) {
112
- this . emit ( 'idle' ) ;
113
- }
114
- }
115
-
116
106
#onResumeInterval( ) : void {
117
107
this . #onInterval( ) ;
118
108
this . #initializeIntervalIfNeeded( ) ;
@@ -127,7 +117,7 @@ export default class PQueue<QueueType extends Queue<RunFunction, EnqueueOptionsT
127
117
if ( delay < 0 ) {
128
118
// Act as the interval was done
129
119
// We don't need to resume it here because it will be resumed on line 160
130
- this . #intervalCount = ( this . #carryoverConcurrencyCount) ? this . #pendingCount : 0 ;
120
+ this . #intervalCount = ( this . #carryoverConcurrencyCount) ? this . #pending : 0 ;
131
121
} else {
132
122
// Act as the interval is pending
133
123
if ( this . #timeoutId === undefined ) {
@@ -156,7 +146,11 @@ export default class PQueue<QueueType extends Queue<RunFunction, EnqueueOptionsT
156
146
157
147
this . #intervalId = undefined ;
158
148
159
- this . #emitEvents( ) ;
149
+ this . emit ( 'empty' ) ;
150
+
151
+ if ( this . #pending === 0 ) {
152
+ this . emit ( 'idle' ) ;
153
+ }
160
154
161
155
return false ;
162
156
}
@@ -199,12 +193,12 @@ export default class PQueue<QueueType extends Queue<RunFunction, EnqueueOptionsT
199
193
}
200
194
201
195
#onInterval( ) : void {
202
- if ( this . #intervalCount === 0 && this . #pendingCount === 0 && this . #intervalId) {
196
+ if ( this . #intervalCount === 0 && this . #pending === 0 && this . #intervalId) {
203
197
clearInterval ( this . #intervalId) ;
204
198
this . #intervalId = undefined ;
205
199
}
206
200
207
- this . #intervalCount = this . #carryoverConcurrencyCount ? this . #pendingCount : 0 ;
201
+ this . #intervalCount = this . #carryoverConcurrencyCount ? this . #pending : 0 ;
208
202
this . #processQueue( ) ;
209
203
}
210
204
@@ -230,48 +224,69 @@ export default class PQueue<QueueType extends Queue<RunFunction, EnqueueOptionsT
230
224
this . #processQueue( ) ;
231
225
}
232
226
227
+ async #throwOnAbort( signal : AbortSignal ) : Promise < never > {
228
+ return new Promise ( ( _resolve , reject ) => {
229
+ signal . addEventListener ( 'abort' , ( ) => {
230
+ // TODO: Reject with signal.throwIfAborted() when targeting Node.js 18
231
+ // TODO: Use ABORT_ERR code when targeting Node.js 16 (https://nodejs.org/docs/latest-v16.x/api/errors.html#abort_err)
232
+ reject ( new AbortError ( 'The task was aborted.' ) ) ;
233
+ } , { once : true } ) ;
234
+ } ) ;
235
+ }
236
+
233
237
/**
234
238
Adds a sync or async task to the queue. Always returns a promise.
235
239
*/
236
- async add < TaskResultType > ( fn : Task < TaskResultType > , options : Partial < EnqueueOptionsType > = { } ) : Promise < TaskResultType > {
237
- return new Promise < TaskResultType > ( ( resolve , reject ) => {
238
- const run = async ( ) : Promise < void > => {
239
- this . #pendingCount++ ;
240
+ async add < TaskResultType > ( function_ : Task < TaskResultType > , options ?: Partial < EnqueueOptionsType > ) : Promise < TaskResultType | void > ;
241
+ async add < TaskResultType > ( function_ : Task < TaskResultType > , options : { throwOnTimeout : true } & Exclude < EnqueueOptionsType , 'throwOnTimeout' > ) : Promise < TaskResultType > ;
242
+ async add < TaskResultType > ( function_ : Task < TaskResultType > , options : Partial < EnqueueOptionsType > = { } ) : Promise < TaskResultType | void > {
243
+ options = {
244
+ timeout : this . timeout ,
245
+ throwOnTimeout : this . #throwOnTimeout,
246
+ ...options ,
247
+ } ;
248
+
249
+ return new Promise ( ( resolve , reject ) => {
250
+ this . #queue. enqueue ( async ( ) => {
251
+ this . #pending++ ;
240
252
this . #intervalCount++ ;
241
253
242
254
try {
255
+ // TODO: Use options.signal?.throwIfAborted() when targeting Node.js 18
243
256
if ( options . signal ?. aborted ) {
244
257
// TODO: Use ABORT_ERR code when targeting Node.js 16 (https://nodejs.org/docs/latest-v16.x/api/errors.html#abort_err)
245
- reject ( new AbortError ( 'The task was aborted.' ) ) ;
246
- return ;
258
+ throw new AbortError ( 'The task was aborted.' ) ;
247
259
}
248
260
249
- const operation = ( this . timeout === undefined && options . timeout === undefined ) ? fn ( { signal : options . signal } ) : pTimeout (
250
- Promise . resolve ( fn ( { signal : options . signal } ) ) ,
251
- ( options . timeout === undefined ? this . timeout : options . timeout ) ! ,
252
- ( ) => {
253
- if ( options . throwOnTimeout === undefined ? this . #throwOnTimeout : options . throwOnTimeout ) {
254
- reject ( timeoutError ) ;
255
- }
261
+ let operation = function_ ( { signal : options . signal } ) ;
256
262
257
- return undefined ;
258
- } ,
259
- ) ;
263
+ if ( options . timeout ) {
264
+ operation = pTimeout ( Promise . resolve ( operation ) , options . timeout ) ;
265
+ }
266
+
267
+ if ( options . signal ) {
268
+ operation = Promise . race ( [ operation , this . #throwOnAbort( options . signal ) ] ) ;
269
+ }
260
270
261
271
const result = await operation ;
262
- resolve ( result ! ) ;
272
+ resolve ( result ) ;
263
273
this . emit ( 'completed' , result ) ;
264
274
} catch ( error : unknown ) {
275
+ if ( error instanceof TimeoutError && ! options . throwOnTimeout ) {
276
+ resolve ( ) ;
277
+ return ;
278
+ }
279
+
265
280
reject ( error ) ;
266
281
this . emit ( 'error' , error ) ;
282
+ } finally {
283
+ this . #next( ) ;
267
284
}
285
+ } , options ) ;
268
286
269
- this . #next( ) ;
270
- } ;
287
+ this . emit ( 'add' ) ;
271
288
272
- this . #queue. enqueue ( run , options ) ;
273
289
this . #tryToStartAnother( ) ;
274
- this . emit ( 'add' ) ;
275
290
} ) ;
276
291
}
277
292
@@ -282,8 +297,16 @@ export default class PQueue<QueueType extends Queue<RunFunction, EnqueueOptionsT
282
297
*/
283
298
async addAll < TaskResultsType > (
284
299
functions : ReadonlyArray < Task < TaskResultsType > > ,
285
- options ?: EnqueueOptionsType ,
286
- ) : Promise < TaskResultsType [ ] > {
300
+ options ?: Partial < EnqueueOptionsType > ,
301
+ ) : Promise < Array < TaskResultsType | void > > ;
302
+ async addAll < TaskResultsType > (
303
+ functions : ReadonlyArray < Task < TaskResultsType > > ,
304
+ options ?: { throwOnTimeout : true } & Partial < Exclude < EnqueueOptionsType , 'throwOnTimeout' > > ,
305
+ ) : Promise < TaskResultsType [ ] >
306
+ async addAll < TaskResultsType > (
307
+ functions : ReadonlyArray < Task < TaskResultsType > > ,
308
+ options ?: Partial < EnqueueOptionsType > ,
309
+ ) : Promise < Array < TaskResultsType | void > > {
287
310
return Promise . all ( functions . map ( async function_ => this . add ( function_ , options ) ) ) ;
288
311
}
289
312
@@ -352,7 +375,7 @@ export default class PQueue<QueueType extends Queue<RunFunction, EnqueueOptionsT
352
375
*/
353
376
async onIdle ( ) : Promise < void > {
354
377
// Instantly resolve if none pending and if nothing else is queued
355
- if ( this . #pendingCount === 0 && this . #queue. size === 0 ) {
378
+ if ( this . #pending === 0 && this . #queue. size === 0 ) {
356
379
return ;
357
380
}
358
381
@@ -395,7 +418,7 @@ export default class PQueue<QueueType extends Queue<RunFunction, EnqueueOptionsT
395
418
Number of running items (no longer in the queue).
396
419
*/
397
420
get pending ( ) : number {
398
- return this . #pendingCount ;
421
+ return this . #pending ;
399
422
}
400
423
401
424
/**
0 commit comments