setTimeout vs. setImmediate Timer Functions in Node.js

Surya Prakash Pandey
JavaScript in Plain English
3 min readJun 1, 2021

--

Node.js is an asynchronous, non-blocking, and event-driven architecture. It is highly inspired by the high concurrency model design of the Nginx web server.

Like the master process and a number of worker process concepts in Nginx, Node.js uses a single-threaded event loop as well as a thread pool. The LibUV library helps Node.js to implement the event loop.

As shown in the image below, this is how different phases in the event loop look like:

Source: https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/

Introduction

Now coming to the execution phase of the event loop, timers are one of the most important functions that help to schedule scripts based on timeouts as well as immediate execution. So, here is a post majorly covering the execution of two important timer functions — setTimeout() and setImmediate() — based on their design to run in separate phases of the event loop.

“When I say so” Execution: setTimeout()

Timers phase in the event loop schedules the execution of funcExecAfterMiliSec callback function, specifies the threshold after which provided callback may be executed. As per Node.js docs,

Technically, the poll phase controls when timers are executed.

“Right after this” Execution ~ setImmediate()

Poll and check phases are responsible for scheduling and execution of this immediate timer event. When the event loop enters the poll phase, its first priority is to exhaust the poll queue. If the poll queue is empty, it looks for scheduled scripts by setImmediate(). If it is there, it ends the poll phase and enters the check phase to execute those scripts. As per Node.js docs,

setImmediate() is actually a special timer that runs in a separate phase of the event loop. It uses a libuv API that schedules callbacks to execute after the poll phase has completed.

Now, the question is — can’t we achieve the same behavior with setTimeout() like this?

As we learned above, both timer events execute in different phases of the event loop. As setImmediate() is designed to execute a script once the current poll phase completes, it means that it’s executed after the poll queue is empty and the event loop is idle; whereas setTimeout() execution is scheduled by the timer phase, which specifies the threshold after which the provided callback may be executed, depending on the poll phase.

But there is a catch here: let’s try running both timer functions in a script which is not within an I/O cycle, which simply means the event loop is not busy in the execution of any callback.

In the above script, it is non-deterministic to guess the order in which the two timers will execute, as they are bound by the performance of the process.

Whereas this script guarantees you first the execution of setImmediate() timer function after “the event loop is done with the execution of file read event from the I/O event queue and event queue is empty.” Hence, the event loop will get to know about the scheduled immediate callback script in the poll phase and move to the check phase for the execution of the same.

Conclusion

Although execution of the script in the immediate queue and timeouts queue will not show you major differences in scenarios where no I/O cycle is involved (hence non-deterministic), in cases when we run those timer functions in specific I/O cycles, then we see the real significance of their different implementation.

That’s all for this one. I will be writing soon about the comparison with process.nextTick() which serves a special purpose. I hope you enjoyed reading this post. Thanks!

More content at plainenglish.io

--

--