Skip to content

Commit a176837

Browse files
dobesvsindresorhus
andauthored
Add error & completed events (#130)
Co-authored-by: Sindre Sorhus <[email protected]>
1 parent 8d0a356 commit a176837

File tree

3 files changed

+99
-5
lines changed

3 files changed

+99
-5
lines changed

readme.md

+37-1
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ If `true`, specifies that any [pending](https://developer.mozilla.org/en-US/docs
112112

113113
Adds a sync or async task to the queue. Always returns a promise.
114114

115+
Note: If your items can potentially throw an exception, you must handle those errors from the returned Promise or they may be reported as an unhandled Promise rejection and potentially cause your process to exit immediately.
116+
115117
##### fn
116118

117119
Type: `Function`
@@ -229,6 +231,40 @@ queue.add(() => Promise.resolve());
229231
queue.add(() => delay(500));
230232
```
231233

234+
#### completed
235+
236+
Emitted when an item completes without error.
237+
238+
```js
239+
import delay from 'delay';
240+
import PQueue from 'p-queue';
241+
242+
const queue = new PQueue({concurrency: 2});
243+
244+
queue.on('completed', result => {
245+
console.log(result);
246+
});
247+
248+
queue.add(() => Promise.resolve('hello, world!'));
249+
```
250+
251+
#### error
252+
253+
Emitted if an item throws an error.
254+
255+
```js
256+
import delay from 'delay';
257+
import PQueue from 'p-queue';
258+
259+
const queue = new PQueue({concurrency: 2});
260+
261+
queue.on('error', error => {
262+
console.error(error);
263+
});
264+
265+
queue.add(() => Promise.reject(new Error('error')));
266+
```
267+
232268
#### idle
233269

234270
Emitted every time the queue becomes empty and all promises have completed; `queue.size === 0 && queue.pending === 0`.
@@ -262,7 +298,7 @@ Emitted every time the add method is called and the number of pending or queued
262298

263299
#### next
264300

265-
Emitted every time a task is completed and the number of pending or queued tasks is decreased.
301+
Emitted every time a task is completed and the number of pending or queued tasks is decreased. This is emitted regardless of whether the task completed normally or with an error.
266302

267303
```js
268304
import delay from 'delay';

source/index.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const timeoutError = new TimeoutError();
1818
/**
1919
Promise queue with concurrency control.
2020
*/
21-
export default class PQueue<QueueType extends Queue<RunFunction, EnqueueOptionsType> = PriorityQueue, EnqueueOptionsType extends QueueAddOptions = DefaultAddOptions> extends EventEmitter<'active' | 'idle' | 'add' | 'next'> {
21+
export default class PQueue<QueueType extends Queue<RunFunction, EnqueueOptionsType> = PriorityQueue, EnqueueOptionsType extends QueueAddOptions = DefaultAddOptions> extends EventEmitter<'active' | 'idle' | 'add' | 'next' | 'completed' | 'error'> {
2222
private readonly _carryoverConcurrencyCount: boolean;
2323

2424
private readonly _isIntervalIgnored: boolean;
@@ -252,11 +252,12 @@ export default class PQueue<QueueType extends Queue<RunFunction, EnqueueOptionsT
252252
}
253253
);
254254

255-
// TODO: Fix this ignore.
256-
// @ts-expect-error
257-
resolve(await operation);
255+
const result = await operation;
256+
resolve(result!);
257+
this.emit('completed', result);
258258
} catch (error: unknown) {
259259
reject(error);
260+
this.emit('error', error);
260261
}
261262

262263
this._next();

test/test.ts

+57
Original file line numberDiff line numberDiff line change
@@ -980,6 +980,63 @@ test('should emit next event when completing task', async t => {
980980
t.is(timesCalled, 3);
981981
});
982982

983+
test('should emit completed / error events', async t => {
984+
const queue = new PQueue({concurrency: 1});
985+
986+
let errorEvents = 0;
987+
let completedEvents = 0;
988+
queue.on('error', () => {
989+
errorEvents++;
990+
});
991+
queue.on('completed', () => {
992+
completedEvents++;
993+
});
994+
995+
const job1 = queue.add(async () => delay(100));
996+
997+
t.is(queue.pending, 1);
998+
t.is(queue.size, 0);
999+
t.is(errorEvents, 0);
1000+
t.is(completedEvents, 0);
1001+
1002+
const job2 = queue.add(async () => {
1003+
await delay(1);
1004+
throw new Error('failure');
1005+
});
1006+
1007+
t.is(queue.pending, 1);
1008+
t.is(queue.size, 1);
1009+
t.is(errorEvents, 0);
1010+
t.is(completedEvents, 0);
1011+
1012+
await job1;
1013+
1014+
t.is(queue.pending, 1);
1015+
t.is(queue.size, 0);
1016+
t.is(errorEvents, 0);
1017+
t.is(completedEvents, 1);
1018+
1019+
await t.throwsAsync(job2);
1020+
1021+
t.is(queue.pending, 0);
1022+
t.is(queue.size, 0);
1023+
t.is(errorEvents, 1);
1024+
t.is(completedEvents, 1);
1025+
1026+
const job3 = queue.add(async () => delay(100));
1027+
1028+
t.is(queue.pending, 1);
1029+
t.is(queue.size, 0);
1030+
t.is(errorEvents, 1);
1031+
t.is(completedEvents, 1);
1032+
1033+
await job3;
1034+
t.is(queue.pending, 0);
1035+
t.is(queue.size, 0);
1036+
t.is(errorEvents, 1);
1037+
t.is(completedEvents, 2);
1038+
});
1039+
9831040
test('should verify timeout overrides passed to add', async t => {
9841041
const queue = new PQueue({timeout: 200, throwOnTimeout: true});
9851042

0 commit comments

Comments
 (0)