We know that a Node.js application is run in a single-threaded fashion. But, it can handle multiple asynchronous operations in the background and exhibits features as if it is a multi-threaded application. At the base level, Node.js is built on C++ which actually allows the existence of multiple threads. While that's not the actual basis, Node.js utilizes the libuv library that allows it to interact with the operating system and utilize available resources efficiently. The library enables asynchronous I/O operations such as file reading, database querying, data transferring over the network, and so on, then it will trigger the registered callback for each completed I/O operation to run. Node.js manage all the callbacks in a mechanism called "event loop".
An event loop is a loop of sequential processes which are grouped into several phases. It handles callbacks of asynchronous I/O operations and asynchronous calls initiated by objects or functions in the main application itself. The phases are as follows.
1. Poll
In this phase, the callbacks from I/O operations are executed. The functions from the main scope of the application are also executed here. There are also two primary microtasks here. The first is the execution of functions called by process.nextTick() that have the highest priority. The second is the execution of callbacks fired by resolve or reject of the Promises. It has a higher priority compared to the callback from I/O operations.
2. Check
This phase will check whether callbacks from the setImmediate() function exists.
3. Close
It will execute callbacks of the close events that are fired by EventEmitter.
4. Timers
In this phase, callbacks of the setTimeout() and setInterval() are called.
5. Pending
Callbacks of specific system events are called in this phase.
![]() |
| Phases of Event Loop |
All registered callbacks in a phase will be completely executed before going to the next phase. Let's take a look at the following example.
const fs = require('fs');
setImmediate(() => { console.log('immediate'); });
Promise.resolve().then(() => { console.log('resolve'); });
process.nextTick(() => { console.log('nexttick1'); });
process.nextTick(() => { console.log('nexttick2'); });
fs.readFile(__filename, () => {
console.log('readfile');
setTimeout(() => { console.log('timeout'); });
setImmediate(() => { console.log('immediate2'); });
});
If we align with the phases described before, the result would be:
nexttick1
nexttick2
resolve
immediate
readfile
immediate2
timeout
Notice that callback of the fs.readFile() is run the last while it would be in the poll phase as an I/O operation callback. It is because the callback is registered in the event loop when the actual I/O operation which is reading a file has been completed and returns the result. Meanwhile, the process.nextTick() method which is called in the third order comes out first. The last setImmediate() method comes before the setTimeout() method, aligning with the phase order.

This article offers a helpful introduction to the Node.js event loop and explains how asynchronous I/O operations allow applications to handle multiple tasks efficiently without blocking the main JavaScript thread. Understanding the roles of libuv, the poll phase, and the check phase helps developers reason about callback execution and asynchronous behavior. These concepts are particularly valuable when building applications that handle network requests, database operations, and other I/O-intensive workloads.
ReplyDeleteFor developers who want to strengthen their understanding of asynchronous programming, a Nodejs Course can help build practical skills in event-driven architecture, promises, callbacks, and non-blocking operations. Learning these fundamentals makes it easier to identify performance bottlenecks and write responsive server-side applications.
Understanding how the event loop works is also useful when developing web APIs and backend services. An Expressjs Course can help developers apply Node.js concepts to routing, middleware, and request handling while building web applications. Combining event-loop knowledge with Express.js development provides a practical foundation for creating efficient, maintainable backend services.
ReplyDelete