Phases of the Node JS Event Loop

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

Image for post
Image for post
Photo by Clément H on Unsplash

In Node.js, you must have encountered one of the above-listed functions. Do you know the difference between them?

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:

Image for post
Image for post

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

Visit https://knowledgescoops.com for more such articles

The Poll Phase

The poll phase handles all of the input/output operations we execute.

All the synchronous JavaScript code you write will be executed in the poll phase of the event loop

Consider that you have written the following 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.

The poll phase handles a lot more than only the IO operations. Read more about it in the Node.js docs.

setTimeout Explanation for Event Loop

Consider the following code snippet:

setTimeout(() => {
console.log('2');
});
console.log('1');

Note that, if the second parameter in setTimeout is not provided, it means a default value of 0 (zero) milliseconds.

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, the setTimeout and console.log(1) statements are the synchronous code that is executed in the poll phase of the event loop.

As soon as this code is executed, a new callback will be added to the callback queue of the timers phase by the Node.js API (as there is only a delay of 0ms for setTimeout in the above example).

After the poll phase is 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. Then, it will find the setTimeout’s callback to be executed and hence ‘2’ gets printed to the console.

The timers phase use a FIFO queueing mechanism to queue multiple callbacks, to be executed in a single iteration of the event loop.

setTimeout( … , 0) does not ensure that the callback is executed immediately, possibly due to a long queue of callbacks or operating system’s task scheduling.

So, in that case, setTimeout(…, 0) might need to wait for a few milliseconds to actually run.

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 is completed.

A 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 check phase.

           ┌───────────────────────────┐
┌─>│ poll │ ---> prints 1
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ check │ ---> prints 2
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ close callbacks │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ timers │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ pending callbacks │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
└──┤ idle, prepare │
└───────────────────────────┘

Difference Between setTimeout and setImmediate

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

The answer:

setImmediate and setTimeout (with 0ms delay) both run the code before the iteration of the next event loop. However, there is a major point to consider:

setImmediate has a higher priority than setTimeout.

How? Let’s see…

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 is 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 be registered in the queue of the check phase.

For the setTimeout execution, the function will be 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 is a nextTickQueue that is executed but 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 the poll phase) is completed, the nextTickQueue will be executed before jumping to the next phase of the event loop.

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 we will get immediately after the code in the current call stack is executed.

Executing long-running codes in the nextTickQueue can starve the execution of different phases of the event loop’s iteration.

Thanks for reading!

Want to read more articles like this?
Follow me on medium @kunaltandon.kt
Connect with me on LinkedIn:
https://www.linkedin.com/in/kunal-tandon/

Written by

Coder • Blogger • Problem Solver • 💁🏼‍♂️ Connect with me on LinkedIn @ http://bit.ly/kunal-tandon

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store