This article is a short follow up to my original article series about Node.js Event Loop. In the original article series, I discussed in detail about Timers, setImmediate
, process.nextTick
, Promises and many more.
However, since Node.js v11.0.0, there are some significant changes to the behavior of setTimeout
, setImmediate
, process.nextTick
and Promises. In this article, I’m going to discuss these new changes along with some comparisons of the functionality between Node < v11.0.0 and Node ≥ v11.0.0. If you miss any of my previous articles about Node.js Event loop, I recommend you read them from the following links and return here to see the new changes introduced in Node v11.0.0.
- Reactor Pattern and the Big Picture
- Timers and Immediates
- Promises, Next-Ticks and Immediates
- Handling I/O
- Event Loop Best Practices
Rationale
If you run the following piece of code in the browser and node separately, you’ll get contradicting results.
In the browser, you will get:
timeout1
timeout2
promise resolve
timeout3
timeout4
However, in Node versions below 11.0.0, you’ll get the following output:
timeout1
timeout2
timeout3
timeout4
promise resolve
In Node JS implementation, process.nextTick
callbacks and microtasks (e.g, promise callbacks) were executed between each phase of the event loop when the C++/JavaScript boundary is crossed. Therefore, all timer callbacks are executed in the timers phase of the event loop before the Promise
callback is executed which resulted in the above output.
However, this contradicting output between the browser and Node has been under discussion for a while and a feature (or a fix) has been landed in Node.js v11.0.0 to follow the browser behavior. With this feature, Node.js v11.0.0 or above will output the following which matches the browser’s output:
timeout1
timeout2
promise resolve
timeout3
timeout4
See the following comparison between Node v10.15.1 and Node v11.10.0:
This change not only affects setTimeout
, but also affectssetImmediate
. Let’s try to run the following code in Node v10 and Node v11 and see how the output is different.
Node v10 and Node v11 clearly give two different outputs as follows:
This behavior is quite the same if you replace Promise.resolve().then
with process.nextTick
, because microtasks are run after the process.nextTick
callbacks are run. Let’s try to run the following snippet:
The output of Node v10 and Node v11 for the above script is as follows:
What happens here?
With the new changes in Node v11, nextTick
callbacks and microtasks will run between each individual setTimeout
and setImmediate
callbacks, even if the timers queue or the immediates queue is not empty. In terms of setTimeout
and Promise
callbacks, the new changes in Node v11 matches the browser behavior which improves the reusability of browser JavaScript in Node.js. However, this significant change could potentially break existing Node.js applications which explicitly rely on the old behavior. Therefore, if you are upgrading to Node v11 or above (preferably the next LTS v12), you might need to consider this as important.