NodeJS provides three ways to call asynchronous functions
- setImmediate()
- setTimeout()
- process.nextTick()
I am writing this blog to explain the basic and advanced usage of these functions.
setImmediate()
Use setImmediate() when you want to execute some function asynchronously, but as soon as possible and after finishing the current block.
When you run following code, callback function passed to setImmediate() is executed immediately after the last line in this code
setImmediate(() => {
console.info('2. Execution of Callback Function');
});
console.info('1. Execution of Main Module Ends');
Console
- Execution of Main Module Ends
- Execution of Callback Function
setTimeout()
Use setTimeout() when you want to execute some function asynchronously, after a specified delay and after finishing the current block.
When you execute this code, callback function passed to setImmediate() is invoked immediately after the last line in this code and after the specified delay, a timeout callback function.
There is one important point though - It is not guaranteed that the callback to setTimeout function is invoked exactly after the specified delay. The reason is explained later on this page.
setTimeout(() => {
console.info('2. Execution of Timeout Callback Function');
}, 10);
console.info('1. Execution of Main Module Ends');
Console
- Execution of Main Module Ends
- Execution of Timeout Callback Function
So far so good. Above information is enough for basic usage of these functions.
Let's dive deep into NodeJS Eventloop to know how these functions are different from each other and from process.nextTick().
Phases Overview (from NodeJS documentation)
1. Timers
In this phase, all timers and intervals are registered as well as tracked. It holds the stack of timers and goes through all active timers one by one. As soon as the timer expires, the callback function is added to the stack that is executed in Poll phase.
This is the reason callback is not executed immediately.
2. Pending Callbacks
Executes I/O callbacks deferred to the next loop iteration.
3. Idle, Prepare
only used internally.
4. Poll
Most of the execution is done in this phase. This is where the javascript code you have written in your file executes.
Node will go through the stack and execute all functions synchronously from oldest to the newest until the queue is empty.
It also retrieves new I/O events; executes I/O related callbacks (almost all with the exception of close callbacks, the ones scheduled by timers, and setImmediate()); node will block here when appropriate.
5. Check
setImmediate() callbacks are invoked here.
6. Close Callbacks
some close callbacks, e.g. socket.on('close', ...)
Note that each phase has its own queue that gets executed before Node moves on the next phase. One iteration or cycle of of this loop is known as 'tick'
Now let's switch back to our main topic.
setImmediate() vs setTimeout()
setImmediate() and setTimeout() are similar, but behave in different ways depending on when they are called.
setImmediate() is designed to execute a script once the current Poll phase completes. Execution of this callback takes place in Check phase (5).
setTimeout() schedules a callback function to be run after a minimum threshold in ms has elapsed. The expiry of timer is checked in Timer phase (1) and execution of callback happens in Poll phase (4).
process.nextTick()
As per NodeJs documentation, process.nextTick() is not technically part of the event loop. Instead, the nextTickQueue will be processed after the current operation is completed, regardless of the current phase of the event loop
process.nextTick() vs setImmediate()
We have two calls that are similar as far as users are concerned, but their names are confusing.
process.nextTick() fires immediately on the same phase
setImmediate() fires on the following iteration or 'tick' of the event loop
In essence, the names should be swapped. process.nextTick() fires more immediately than setImmediate(), but this is an artifact of the past which is unlikely to change.
From NodeJS documentation: -> We recommend developers use setImmediate() in all cases because it's easier to reason about.
Here is an example putting together all functions
setTimeout(() => {
console.info('4. Execution of Timeout Callback Function');
}, 10);
setImmediate(() => {
console.info('3. Execution of Immediate Callback Function');
});
process.nextTick(() => {
console.info('2. Execution of NextTick Callback Function');
})
console.info('1. Execution of Main Module Ends');
Console
- Execution of Main Module Ends
- Execution of NextTick Callback Function
- Execution of Immediate Callback Function
- Execution of Timeout Callback Function
Refer NodeJS documentation for more information: https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/
Top comments (2)
Thank you for this wonderful article.
In the second paragraph discussing setTimeout, I noticed a mention of setImmediate. Could you please clarify if it was intended to reference setTimeout instead? This part confused me a bit.
4 is executing before 3 when i ran the code