Skip to content

Commit 3317426

Browse files
OmarDarwishOmar Darwish
authored andcommitted
Clarify when nextTick queue is processed
Define an operation. Give example of dedup. Remove empty section Fix trigger happy deletions Remove modififed REPL link Spellcheck Deduplication section Address Nits * Remove italics. * Change italics to bold Move Deduplication sectino down Update locale/en/docs/guides/event-loop-timers-and-nexttick.md Co-Authored-By: OmarDarwish <om.drwsh@gmail.com> Update locale/en/docs/guides/event-loop-timers-and-nexttick.md Co-Authored-By: OmarDarwish <om.drwsh@gmail.com>
1 parent 6ff7342 commit 3317426

File tree

1 file changed

+55
-2
lines changed

1 file changed

+55
-2
lines changed

locale/en/docs/guides/event-loop-timers-and-nexttick.md

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,11 @@ within an I/O cycle, independently of how many timers are present.
293293
You may have noticed that `process.nextTick()` was not displayed in the
294294
diagram, even though it's a part of the asynchronous API. This is because
295295
`process.nextTick()` is not technically part of the event loop. Instead,
296-
the `nextTickQueue` will be processed after the current operation
297-
completes, regardless of the current phase of the event loop.
296+
the `nextTickQueue` will be processed after the current operation is
297+
completed, regardless of the current phase of the event loop. Here,
298+
an *operation* is defined as a transition from the
299+
underlying C/C++ handler, and handling the JavaScript that needs to be
300+
executed.
298301

299302
Looking back at our diagram, any time you call `process.nextTick()` in a
300303
given phase, all callbacks passed to `process.nextTick()` will be
@@ -395,6 +398,56 @@ To get around this, the `'listening'` event is queued in a `nextTick()`
395398
to allow the script to run to completion. This allows the user to set
396399
any event handlers they want.
397400

401+
### Deduplication
402+
403+
For the `timers` and `check` phases, there is a single transition
404+
between C to JavaScript for multiple immediates and timers. This deduplication
405+
is a form of optimization, which may produce some unexpected side effects.
406+
Take this code snippet as an example:
407+
408+
```js
409+
// dedup.js
410+
const foo = [1, 2];
411+
const bar = ['a', 'b'];
412+
413+
foo.forEach(num => {
414+
setImmediate(() => {
415+
console.log('setImmediate', num);
416+
bar.forEach(char => {
417+
process.nextTick(() => {
418+
console.log('process.nextTick', char);
419+
});
420+
});
421+
});
422+
});
423+
```
424+
```bash
425+
$ node dedup.js
426+
setImmediate 1
427+
setImmediate 2
428+
process.nextTick a
429+
process.nextTick b
430+
process.nextTick a
431+
process.nextTick b
432+
```
433+
434+
The main thread adds two `setImmediate()` events, which when processed
435+
will add two `process.nextTick()` events. When the event loop reaches
436+
the `check` phase, it sees that there are currently two events created by
437+
`setImmediate()`. The first event is grabbed and processed, which prints
438+
and adds two events to the `nextTickQueue`.
439+
440+
Because of deduplication, the event loop does not transition back to the
441+
C/C++ layer to check if there are items in the `nextTickQueue` immediately. It
442+
instead continues to process any remaining `setImmediate()` events, of which
443+
one currently remains. After processing this event, two more events are
444+
added to the `nextTickQueue` for a total of four events.
445+
446+
At this point, all previously added `setImmediate()` events have been processed.
447+
The `nextTickQueue` is now checked, and events are processed in FIFO order. When
448+
this `nextTickQueue` is emptied, the event loop considers all operations to have
449+
been completed for the current phase and transitions to the next phase.
450+
398451
## `process.nextTick()` vs `setImmediate()`
399452

400453
We have two calls that are similar as far as users are concerned, but

0 commit comments

Comments
 (0)