π Question: What do you think this code prints when it runs?
π‘ Guess the output before reading further!
β Have you ever been told to never block the event loop? Why do you think that is?
`
setTimeout(() => { console.log("time out") }, 0);
setImmediate(() => { console.log("immediate"); });
function callNextTick() {
process.nextTick(callNextTick);
}
callNextTick();
console.log("This is a weird code");`
To understand why this code completely blocks the event loop, we need to understand Node.js's asynchronous execution model.
Expected Behavior (Without nextTick)
Normally, the event loop processes tasks in phases:
Timers Phase β Executes setTimeout (even with 0ms delay).
Check Phase β Executes setImmediate.
But here, both setTimeout and setImmediate will never get a chance to execute. Why is that?
Understanding process.nextTick()
Unlike setTimeout or setImmediate, process.nextTick() is not part of the normal event loop phases.
It has its own special queue called the nextTickQueue.
Callbacks in this queue run right after the current code finishes, before the event loop moves to any phase.
How the Code Executes Step by Step
1.setTimeout(() => { console.log("time out") }, 0) is scheduled for the timers phase.
2.setImmediate(() => { console.log("immediate"); }) is scheduled for the check phase.
3.callNextTick() is defined and immediately called.
4.process.nextTick(callNextTick) adds the function to the nextTick queue.
- The synchronous line console.log("This is a weird code") executes.
- Node checks the nextTick queue after the current code finishes.
- callNextTick runs from the nextTick queue.
- Inside callNextTick, process.nextTick(callNextTick) schedules itself again.
Steps 6β8 repeat infinitely, because nextTick always runs before the event loop moves to any phase.
Result: The event loop never reaches timers, I/O, or check phases, so setTimeout and setImmediate callbacks are never executed. This is called starving the event loop or blocking the event loop.
Key Takeaways
β nextTick is not part of the event loop β It runs before the loop proceeds.
β Recursive nextTick = Event Loop Blockage β Starves timers, I/O, and setImmediate.
β Avoid nextTick recursion β Use setImmediate if you need to defer execution without blocking.
Top comments (0)