From 431bfe177ff11ba9dc6e6b18bfa638660c976456 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Mon, 6 Jul 2020 08:00:51 -0700 Subject: [PATCH] doc: add note about multiple sync events and once Fixes: https://github.com/nodejs/node/issues/32431 PR-URL: https://github.com/nodejs/node/pull/34220 Reviewed-By: Luigi Pinca Reviewed-By: Anto Aravinth Reviewed-By: Trivikram Kamat --- doc/api/events.md | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/doc/api/events.md b/doc/api/events.md index 84f2fe199684a9..995351a64a2223 100644 --- a/doc/api/events.md +++ b/doc/api/events.md @@ -892,6 +892,60 @@ ee.emit('error', new Error('boom')); // Prints: ok boom ``` +### Awaiting multiple events emitted on `process.nextTick()` + +There is an edge case worth noting when using the `events.once()` function +to await multiple events emitted on in the same batch of `process.nextTick()` +operations, or whenever multiple events are emitted synchronously. Specifically, +because the `process.nextTick()` queue is drained before the `Promise` microtask +queue, and because `EventEmitter` emits all events synchronously, it is possible +for `events.once()` to miss an event. + +```js +const { EventEmitter, once } = require('events'); + +const myEE = new EventEmitter(); + +async function foo() { + await once(myEE, 'bar'); + console.log('bar'); + + // This Promise will never resolve because the 'foo' event will + // have already been emitted before the Promise is created. + await once(myEE, 'foo'); + console.log('foo'); +} + +process.nextTick(() => { + myEE.emit('bar'); + myEE.emit('foo'); +}); + +foo().then(() => console.log('done')); +``` + +To catch both events, create each of the Promises *before* awaiting either +of them, then it becomes possible to use `Promise.all()`, `Promise.race()`, +or `Promise.allSettled()`: + +```js +const { EventEmitter, once } = require('events'); + +const myEE = new EventEmitter(); + +async function foo() { + await Promise.all([once(myEE, 'bar'), once(myEE, 'foo')]); + console.log('foo', 'bar'); +} + +process.nextTick(() => { + myEE.emit('bar'); + myEE.emit('foo'); +}); + +foo().then(() => console.log('done')); +``` + ## `events.captureRejections`