| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1489,64 +1489,75 @@ foo(ee, 'foo', ac.signal); | |||
| 1489 | 1489 | ac.abort(); // Prints: Waiting for the event was canceled! | |
| 1490 | 1490 | ``` | |
| 1491 | 1491 | ||
| 1492 | - ### Awaiting multiple events emitted on `process.nextTick()` | ||
| 1492 | + ### Caveats when awaiting multiple events | ||
| 1493 | 1493 | ||
| 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.) | ||
| 1500 | 1511 | ||
| 1501 | 1512 | ```mjs | |
| 1502 | 1513 | import { EventEmitter, once } from 'node:events'; | |
| 1503 | 1514 | import process from 'node:process'; | |
| 1504 | 1515 | ||
| 1505 | 1516 | const myEE = new EventEmitter(); | |
| 1506 | 1517 | ||
| 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() { | ||
| 1513 | 1519 | await once(myEE, 'foo'); | |
| 1514 | 1520 | 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'); | ||
| 1515 | 1526 | } | |
| 1516 | 1527 | ||
| 1517 | 1528 | process.nextTick(() => { | |
| 1518 | - myEE.emit('bar'); | ||
| 1519 | 1529 | myEE.emit('foo'); | |
| 1530 | + myEE.emit('bar'); | ||
| 1520 | 1531 | }); | |
| 1521 | 1532 | ||
| 1522 | - foo().then(() => console.log('done')); | ||
| 1533 | + listen().then(() => console.log('done')); | ||
| 1523 | 1534 | ``` | |
| 1524 | 1535 | ||
| 1525 | 1536 | ```cjs | |
| 1526 | 1537 | const { EventEmitter, once } = require('node:events'); | |
| 1527 | 1538 | ||
| 1528 | 1539 | const myEE = new EventEmitter(); | |
| 1529 | 1540 | ||
| 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() { | ||
| 1536 | 1542 | await once(myEE, 'foo'); | |
| 1537 | 1543 | 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'); | ||
| 1538 | 1549 | } | |
| 1539 | 1550 | ||
| 1540 | 1551 | process.nextTick(() => { | |
| 1541 | - myEE.emit('bar'); | ||
| 1542 | 1552 | myEE.emit('foo'); | |
| 1553 | + myEE.emit('bar'); | ||
| 1543 | 1554 | }); | |
| 1544 | 1555 | ||
| 1545 | - foo().then(() => console.log('done')); | ||
| 1556 | + listen().then(() => console.log('done')); | ||
| 1546 | 1557 | ``` | |
| 1547 | 1558 | ||
| 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()`, | ||
| 1550 | 1561 | or `Promise.allSettled()`: | |
| 1551 | 1562 | ||
| 1552 | 1563 | ```mjs | |
@@ -1555,35 +1566,41 @@ import process from 'node:process'; | |||
| 1555 | 1566 | ||
| 1556 | 1567 | const myEE = new EventEmitter(); | |
| 1557 | 1568 | ||
| 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 | + ]); | ||
| 1560 | 1574 | console.log('foo', 'bar'); | |
| 1561 | 1575 | } | |
| 1562 | 1576 | ||
| 1563 | 1577 | process.nextTick(() => { | |
| 1564 | - myEE.emit('bar'); | ||
| 1565 | 1578 | myEE.emit('foo'); | |
| 1579 | + myEE.emit('bar'); | ||
| 1566 | 1580 | }); | |
| 1567 | 1581 | ||
| 1568 | - foo().then(() => console.log('done')); | ||
| 1582 | + listen().then(() => console.log('done')); | ||
| 1569 | 1583 | ``` | |
| 1570 | 1584 | ||
| 1571 | 1585 | ```cjs | |
| 1572 | 1586 | const { EventEmitter, once } = require('node:events'); | |
| 1573 | 1587 | ||
| 1574 | 1588 | const myEE = new EventEmitter(); | |
| 1575 | 1589 | ||
| 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 | + ]); | ||
| 1578 | 1595 | console.log('foo', 'bar'); | |
| 1579 | 1596 | } | |
| 1580 | 1597 | ||
| 1581 | 1598 | process.nextTick(() => { | |
| 1582 | - myEE.emit('bar'); | ||
| 1583 | 1599 | myEE.emit('foo'); | |
| 1600 | + myEE.emit('bar'); | ||
| 1584 | 1601 | }); | |
| 1585 | 1602 | ||
| 1586 | - foo().then(() => console.log('done')); | ||
| 1603 | + listen().then(() => console.log('done')); | ||
| 1587 | 1604 | ``` | |
| 1588 | 1605 | ||
| 1589 | 1606 | ## `events.captureRejections` | |
| Back | FazBrowse Home | New Git URL |
0 commit comments