@@ -1489,64 +1489,75 @@ foo(ee, 'foo', ac.signal);
14891489ac .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
15021513import { EventEmitter , once } from ' node:events' ;
15031514import process from ' node:process' ;
15041515
15051516const 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
15171528process .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
15261537const { EventEmitter , once } = require (' node:events' );
15271538
15281539const 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
15401551process .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() ` ,
15501561or ` Promise.allSettled() ` :
15511562
15521563``` mjs
@@ -1555,35 +1566,41 @@ import process from 'node:process';
15551566
15561567const 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
15631577process .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
15721586const { EventEmitter , once } = require (' node:events' );
15731587
15741588const 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
15811598process .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