The Event Loop is an important part of Node.js. It helps Node.js handle asynchronous operations without blocking the main JavaScript thread while waiting for many I/O operations to complete.
The Event Loop is a mechanism used by Node.js to manage asynchronous callbacks. It allows Node.js to continue handling other work while operations such as timers and file or network I/O are pending.
For example, Node.js can:
setTimeout().console.log("First");
setTimeout(function() {
console.log("Second");
}, 1000);
console.log("Third");
First
Third
Second
The timer callback runs after the synchronous statements. The delay is approximately one second, not an exact guarantee.
When Node.js executes a program, synchronous statements run first. Asynchronous operations can be scheduled, and their callbacks become eligible to run when the relevant operation or timer is ready.
Synchronous code executes in sequence. An asynchronous operation can allow the program to continue while it waits for a result.
console.log("A");
console.log("B");
console.log("C");
A
B
C
console.log("A");
setTimeout(function() {
console.log("B");
}, 0);
console.log("C");
A
C
B
Even with a delay of zero milliseconds, the timer callback does not interrupt the synchronous statements.
The setTimeout() function schedules a callback to run
after at least the specified delay, when the Event Loop can execute it.
console.log("Program started");
setTimeout(function() {
console.log("Timer completed");
}, 2000);
console.log("Program continues");
Program started
Program continues
Timer completed
The program does not wait synchronously for the timer. The timer callback runs later, after the delay has elapsed and the Event Loop can execute it.
Promise callbacks, such as those passed to .then(),
are scheduled as microtasks. In ordinary Node.js code, pending
Promise microtasks are processed before the Event Loop continues
to later timer callbacks.
console.log("Start");
setTimeout(function() {
console.log("Timer");
}, 0);
Promise.resolve().then(function() {
console.log("Promise");
});
console.log("End");
Start
End
Promise
Timer
The synchronous code runs first, followed by the Promise microtask and then the timer callback in this example.
Node.js organizes Event Loop work into phases. Each phase handles certain kinds of callbacks.
| Phase | Purpose |
|---|---|
| Timers | Runs eligible callbacks scheduled by setTimeout() and setInterval(). |
| Pending Callbacks | Runs certain system-level I/O callbacks deferred to this phase. |
| Idle, Prepare | Internal Node.js processing. |
| Poll | Processes many I/O-related callbacks and waits for I/O when appropriate. |
| Check | Runs callbacks scheduled using setImmediate(). |
| Close Callbacks | Handles certain close events, such as socket close callbacks. |
process.nextTick() callbacks are not separate Event Loop
phases in this table. Their scheduling and execution have their own
rules.
Both functions schedule callbacks, but they are associated with different parts of the Event Loop.
setTimeout(function() {
console.log("Timeout callback");
}, 0);
setImmediate(function() {
console.log("Immediate callback");
});
When run directly from the main module, the order of these two messages is not guaranteed across all circumstances.
Inside an I/O callback, setImmediate() is
generally executed before a zero-delay timer scheduled in
that callback.
process.nextTick() schedules a callback to run after
the current JavaScript operation finishes, before the Event Loop
continues to its next phase.
console.log("One");
process.nextTick(function() {
console.log("Two");
});
console.log("Three");
One
Three
Two
The nextTick callback does not interrupt the current synchronous code. Node.js processes it afterward.
Select the correct answer for each question.
console.log("A");
setTimeout(() => console.log("B"), 0);
console.log("C");