Eventloop in NodeJS: setTimeout, setImmediate vs process.nextTick

Jeevan D C
DKatalis
Published in
4 min readFeb 10, 2021

Contents:
What is the Event Loop?
So, when to use setTimeout, setImmediate, process.nextTick?
Issue with setTimeout?
Precedence within Eventloop
Take aways

Consider below code, what would be the order on execution even though it’s apparent that they do the same thing (executing the callback)?

current event loop
nextTick
timeout
immediate

What is the order of execution of setTimeout, setImmediate, process.nextTick ?
To answer this let’s understand EventLoop.

What is the Event Loop?

The event loop is what allows Node.js to perform non-blocking I/O operations — despite the fact that JavaScript is single-threaded — by offloading operations to the system kernel whenever possible.

Since most modern kernels are multi-threaded, they can handle multiple operations executing in the background. When one of these operations completes, the kernel tells Node.js so that the appropriate callback may be added to the poll queue to eventually be executed. We’ll explain this in further detail later in this topic.

Analogy:

In a coffee shop, like a Barista(read EventLoop) takes orders of every customers queued(read IOs) and the preparation of coffee, handing out coffee, or packing the take away is done by different different clerks (read workers aka c++ apis in different thread) is how an EventLoop (Single Thread — single cashier) works.

This below diagram shows the order of execution of different phase in event Loop

  • timers: this phase executes callbacks scheduled by setTimeout() and setInterval().
  • pending callbacks: executes I/O callbacks deferred to the next loop iteration.
  • idle, prepare: only used internally.
  • poll: retrieve new I/O events; execute 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.
  • check: setImmediate() callbacks are invoked here.
  • close callbacks: some close callbacks, e.g. socket.on('close', ...)

So, when to use setTimeout, setImmediate, process.nextTick?

setTimeout: Usecases of timers

setImmediate() vs process.nextTick()

Now let’s look at the differences between setImmediate() and process.nextTick() and when to use which.

  • setImmediate() is processed in the Check handlers phase, while process.nextTick() is processed at the starting of the event loop and between each phase of the event loop.
  1. On any given context process.nextTick() has higher priority over setImmediate().
But I run before that
I run immediately

3. If process.nextTick() is called in a given phase, all the callbacks passed to process.nextTick() will be resolved before the event loop continues. This will block the event loop and create I/O Starvation if process.nextTick() is called recursively.

Start
Processing nextTick cb 1
Processing nextTick cb 2
Processing nextTick cb 3
Processing nextTick cb 4
Processing nextTick cb 5
Processing nextTick cb 6
Processing nextTick cb 7
Processing nextTick cb 8
Processing nextTick cb 9
Processing nextTick cb 10
...

As you can see recursive calls to process.nextTick() are processed continuously and I/O is starved. So setImmediate() and setTimeout() callbacks won't be executed.

4. Unlike process.nextTick(), recursive calls to setImmediate() won't block the event loop, because every recursive call is executed only on the next event loop iteration.

Start
Processing setImmediate cb 1
Processing setImmediate cb 2
Processing setImmediate cb 3
Processing setImmediate cb 4
...
Processing setImmediate cb 503
Processing setImmediate cb 504
setTimeout executed
Processing setImmediate cb 505
Processing setImmediate cb 506
...

Here even though setImmediate() is called recursively, it won't block the event loop and the setTimeout() callback is executed after the specified timeout.

Issue with setTimeout?

Predict the order of execution of Foo, Bar, Goo, Poo

Is it Foo, Poo, Goo, Poo ?

Output:

Visualize what actually happened here with callstacks and queues.

link

Precedence within Eventloop

callstack > microTasks > macroTasks

Try here

More on event loop queues here.

Take aways

As the official docs, always use setImmediate().

We recommend developers use setImmediate() in all cases because it’s easier to reason about.

  • Non-IO loops: Execution order process.nextTick() > setTimeout() > setImmediate()and other timers in non IO loops
  • IO loops: Execution order process.nextTick() > setImmediate() > setTimeout() and other timers in non IO loops
  • setTimeout isn’t reliable always

Like what you’re reading? Why not join our team and meet the like-minded team behind this? Join us !

--

--