Explaining process.nextTick, setImmediate, and setTimeout for Phases of Event Loop

July 27, 2019


In Node js, you must have encountered any of the above-listed functions. Do really know the difference between the three?
In this article, we will discuss each of the function one by one and also compare the difference between them.
The different phases of an event loop are:

In this article, we will focus on the poll, timers and check phase of the event loop.

The “poll” phase

The poll phase handles all of the Input/Output operations that get executed by us.
All the synchronous JavaScript code that you write will get executed in the poll phase of the event loop
Consider you have written the code
console.log('1');
console.log('2');

With respect to the Event loop

           ┌───────────────────────────┐
        ┌─>│           poll            │ ---> prints 1, then 2
        │  └─────────────┬─────────────┘
        │  ┌─────────────┴─────────────┐
        │  │           check           │
        │  └─────────────┬─────────────┘
        │  ┌─────────────┴─────────────┐
        │  │       close callbacks     │
        │  └─────────────┬─────────────┘
        │  ┌─────────────┴─────────────┐
        │  │           timers          │
        │  └─────────────┬─────────────┘
        │  ┌─────────────┴─────────────┐
        │  │     pending callbacks     │
        │  └─────────────┬─────────────┘
        │  ┌─────────────┴─────────────┐
        └──┤        idle, prepare      │
           └───────────────────────────┘
All of the code will be executed when the event loop is in the poll phase of its iteration.

setTimeout Explanation wrt Event Loop

Consider the following code snippet,
setTimeout(() => {
    console.log('2');
});
console.log('1');
This will print the output as
1
2           ┌───────────────────────────┐
        ┌─>│           poll            │ ---> prints 1
        │  └─────────────┬─────────────┘
        │  ┌─────────────┴─────────────┐
        │  │           check           │
        │  └─────────────┬─────────────┘
        │  ┌─────────────┴─────────────┐
        │  │       close callbacks     │
        │  └─────────────┬─────────────┘
        │  ┌─────────────┴─────────────┐
        │  │           timers          │ ---> prints 2
        │  └─────────────┬─────────────┘
        │  ┌─────────────┴─────────────┐
        │  │     pending callbacks     │
        │  └─────────────┬─────────────┘
        │  ┌─────────────┴─────────────┐
        └──┤        idle, prepare      │
           └───────────────────────────┘ 
In an event loop, all of the synchronous JavaScript code runs in the “poll”phase of the event loop. In the above code, setTimeout and console.log(1) statement are the synchronous code that gets executed in the poll phase of the event loop.
As soon as this code gets executed, a new callback will be added to the callback queue of the “timers” phase by the NodeJs APIs(as there is only a delay of 0ms for setTimeout in the above example).
After the “poll” phase gets completed for an event loop iteration, the event loop continues its execution through all of the phases one by one until the “timers” phase is reached.
As soon as the event loop reaches the “timers” phase, the event loop will go through the timers queue and then it will find the setTimeout’s callback to be executed and hence ‘2’ gets printed to the console.

setImmediate

The Event loop is an infinitely running task which keeps looping infinitely. A callback executed with setImmediate will be executed in the “check” phase of the event loop which runs immediately after the “poll” phase gets completed.
setImmediate code snippet will look like:
setImmediate(() => {
    console.log('2');
});
console.log('1');
This will print the output
1
2
setImmediate puts the callback in the “check” phase of the event loop.
As soon as the synchronous code is executed in the poll phase, the event loop will end the poll phase after executing the current call stack and jumps to the check phase of the event loop. In the check phase, it will find a queue of callbacks that will get executed once the event loop enters the checkphase.
           ┌───────────────────────────┐
        ┌─>│           poll            │ ---> prints 1
        │  └─────────────┬─────────────┘
        │  ┌─────────────┴─────────────┐
        │  │           check           │ ---> prints 2
        │  └─────────────┬─────────────┘
        │  ┌─────────────┴─────────────┐
        │  │       close callbacks     │
        │  └─────────────┬─────────────┘
        │  ┌─────────────┴─────────────┐
        │  │           timers          │
        │  └─────────────┬─────────────┘
        │  ┌─────────────┴─────────────┐
        │  │     pending callbacks     │
        │  └─────────────┬─────────────┘
        │  ┌─────────────┴─────────────┐
        └──┤        idle, prepare      │
           └───────────────────────────┘



Question:

At this point, you might have been wondering what is the difference between setTimeout with no second param and setImmediate.

Answer:

setImmediate and setTimeout(with 0ms delayboth run the code before the iteration of the next event loop. However, there a major point to consider:
setImmediate has a higher priority than setTimeout
How? let’s see…
setTimeout(() => {
    console.log('3');
});setImmediate(() => {
    console.log('2');
});console.log('1');
This will print the output as
1
2
3
This means that if setTimeout and setImmediate need to be executed simultaneously, setImmediate will execute first.
In the above code, the synchronous code gets executed in the poll phase of the event loop which will print the value ‘1’ in the console.
For the setImmediate execution, the function will get registered in the queue of the check phase.
For the setTimeout execution, the function will get registered in the queue of the timers phase.
The event loop for the above code will execute like this:
           ┌───────────────────────────┐
        ┌─>│           poll            │ ---> prints 1
        │  └─────────────┬─────────────┘
        │  ┌─────────────┴─────────────┐
        │  │           check           │ ---> prints 2
        │  └─────────────┬─────────────┘
        │  ┌─────────────┴─────────────┐
        │  │       close callbacks     │
        │  └─────────────┬─────────────┘
        │  ┌─────────────┴─────────────┐
        │  │           timers          │ ---> prints 3
        │  └─────────────┬─────────────┘
        │  ┌─────────────┴─────────────┐
        │  │     pending callbacks     │
        │  └─────────────┬─────────────┘
        │  ┌─────────────┴─────────────┐
        └──┤        idle, prepare      │
           └───────────────────────────┘
Hence we get the output
1
2
3



process.nextTick

After the execution of each phase of the event loop and before starting the next phase of the event loop, there exists a nextTickQueue that gets executed that isn’t officially a part of the event loop.
Any callback provided in the process.nextTick gets registered in the nextTickQueue of the next phase. As soon as the current phase(say pollphase) gets completed, the nextTickQueue will be executed before jumping to the next phase of the event loop.
process.nextTick(() => {
    console.log('2');
});setImmediate(() => {
    console.log('3');
});console.log('1');
In the above code snippet, the code will execute in the following way
           ┌───────────────────────────┐
        ┌─>│           poll            │ ---> prints 1
        │  └─────────────┬─────────────┘
        │           nextTickQueue        ---> prints 2   
        │  ┌─────────────┴─────────────┐
        │  │           check           │ ---> prints 3
        │  └─────────────┬─────────────┘
        │           nextTickQueue
        │  ┌─────────────┴─────────────┐
        │  │       close callbacks     │
        │  └─────────────┬─────────────┘
 nextTickQueue      nextTickQueue
        │  ┌─────────────┴─────────────┐
        │  │           timers          │
        │  └─────────────┬─────────────┘
        │           nextTickQueue
        │  ┌─────────────┴─────────────┐
        │  │     pending callbacks     │
        │  └─────────────┬─────────────┘
        │           nextTickQueue
        │  ┌─────────────┴─────────────┐
        └──┤        idle, prepare      │
           └───────────────────────────┘
Hence, the code executed with the process.nextTick is the asynchronous code that will get immediately after the code in the current call stack will get executed.

You Might Also Like

0 comments

Follow by Email