Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit db610b9

Browse filesBrowse files
Renegade334aduh95
authored andcommitted
doc: clarify async caveats for events.once()
PR-URL: #61572 Refs: #34220 Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
1 parent ea8886f commit db610b9
Copy full SHA for db610b9

1 file changed

+50-33Lines changed: 50 additions & 33 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎doc/api/events.md‎

Copy file name to clipboardExpand all lines: doc/api/events.md
+50-33Lines changed: 50 additions & 33 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -1489,64 +1489,75 @@ foo(ee, 'foo', ac.signal);
14891489
ac.abort(); // Prints: Waiting for the event was canceled!
14901490
```
14911491

1492-
### Awaiting multiple events emitted on `process.nextTick()`
1492+
### Caveats when awaiting multiple events
14931493

1494-
There is an edge case worth noting when using the `events.once()` function
1495-
to await multiple events emitted on in the same batch of `process.nextTick()`
1496-
operations, or whenever multiple events are emitted synchronously. Specifically,
1497-
because the `process.nextTick()` queue is drained before the `Promise` microtask
1498-
queue, and because `EventEmitter` emits all events synchronously, it is possible
1499-
for `events.once()` to miss an event.
1494+
It is important to be aware of execution order when using the `events.once()`
1495+
method to await multiple events.
1496+
1497+
Conventional event listeners are called synchronously when the event is
1498+
emitted. This guarantees that execution will not proceed beyond the emitted
1499+
event until all listeners have finished executing.
1500+
1501+
The same is _not_ true when awaiting Promises returned by `events.once()`.
1502+
Promise tasks are not handled until after the current execution stack runs to
1503+
completion, which means that multiple events could be emitted before
1504+
asynchronous execution continues from the relevant `await` statement.
1505+
1506+
As a result, events can be "missed" if a series of `await events.once()`
1507+
statements is used to listen to multiple events, since there might be times
1508+
where more than one event is emitted during the same phase of the event loop.
1509+
(The same is true when using `process.nextTick()` to emit events, because the
1510+
tasks queued by `process.nextTick()` are executed before Promise tasks.)
15001511

15011512
```mjs
15021513
import { EventEmitter, once } from 'node:events';
15031514
import process from 'node:process';
15041515

15051516
const myEE = new EventEmitter();
15061517

1507-
async function foo() {
1508-
await once(myEE, 'bar');
1509-
console.log('bar');
1510-
1511-
// This Promise will never resolve because the 'foo' event will
1512-
// have already been emitted before the Promise is created.
1518+
async function listen() {
15131519
await once(myEE, 'foo');
15141520
console.log('foo');
1521+
1522+
// This Promise will never resolve, because the 'bar' event will
1523+
// have already been emitted before the next line is executed.
1524+
await once(myEE, 'bar');
1525+
console.log('bar');
15151526
}
15161527

15171528
process.nextTick(() => {
1518-
myEE.emit('bar');
15191529
myEE.emit('foo');
1530+
myEE.emit('bar');
15201531
});
15211532

1522-
foo().then(() => console.log('done'));
1533+
listen().then(() => console.log('done'));
15231534
```
15241535

15251536
```cjs
15261537
const { EventEmitter, once } = require('node:events');
15271538

15281539
const myEE = new EventEmitter();
15291540

1530-
async function foo() {
1531-
await once(myEE, 'bar');
1532-
console.log('bar');
1533-
1534-
// This Promise will never resolve because the 'foo' event will
1535-
// have already been emitted before the Promise is created.
1541+
async function listen() {
15361542
await once(myEE, 'foo');
15371543
console.log('foo');
1544+
1545+
// This Promise will never resolve, because the 'bar' event will
1546+
// have already been emitted before the next line is executed.
1547+
await once(myEE, 'bar');
1548+
console.log('bar');
15381549
}
15391550

15401551
process.nextTick(() => {
1541-
myEE.emit('bar');
15421552
myEE.emit('foo');
1553+
myEE.emit('bar');
15431554
});
15441555

1545-
foo().then(() => console.log('done'));
1556+
listen().then(() => console.log('done'));
15461557
```
15471558

1548-
To catch both events, create each of the Promises _before_ awaiting either
1549-
of them, then it becomes possible to use `Promise.all()`, `Promise.race()`,
1559+
To catch multiple events, create all of the Promises _before_ awaiting any of
1560+
them. This is usually made easier by using `Promise.all()`, `Promise.race()`,
15501561
or `Promise.allSettled()`:
15511562

15521563
```mjs
@@ -1555,35 +1566,41 @@ import process from 'node:process';
15551566

15561567
const myEE = new EventEmitter();
15571568

1558-
async function foo() {
1559-
await Promise.all([once(myEE, 'bar'), once(myEE, 'foo')]);
1569+
async function listen() {
1570+
await Promise.all([
1571+
once(myEE, 'foo'),
1572+
once(myEE, 'bar'),
1573+
]);
15601574
console.log('foo', 'bar');
15611575
}
15621576

15631577
process.nextTick(() => {
1564-
myEE.emit('bar');
15651578
myEE.emit('foo');
1579+
myEE.emit('bar');
15661580
});
15671581

1568-
foo().then(() => console.log('done'));
1582+
listen().then(() => console.log('done'));
15691583
```
15701584

15711585
```cjs
15721586
const { EventEmitter, once } = require('node:events');
15731587

15741588
const myEE = new EventEmitter();
15751589

1576-
async function foo() {
1577-
await Promise.all([once(myEE, 'bar'), once(myEE, 'foo')]);
1590+
async function listen() {
1591+
await Promise.all([
1592+
once(myEE, 'bar'),
1593+
once(myEE, 'foo'),
1594+
]);
15781595
console.log('foo', 'bar');
15791596
}
15801597

15811598
process.nextTick(() => {
1582-
myEE.emit('bar');
15831599
myEE.emit('foo');
1600+
myEE.emit('bar');
15841601
});
15851602

1586-
foo().then(() => console.log('done'));
1603+
listen().then(() => console.log('done'));
15871604
```
15881605

15891606
## `events.captureRejections`

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.