The Node.js Event Loop Demystified
The Single Thread Myth
Javascript is single-threaded. This means it can only execute one piece of code at a time. So how can a Node.js web server handle thousands of simultaneous file uploads and database queries without freezing? The secret is the Event Loop and asynchronous non-blocking I/O.
How it Actually Works
When Node.js receives a request that requires time to process (like reading a heavy file or making a network request to an API), it does not wait for it to finish. Instead, it offloads the heavy lifting to the operating system (using a C++ library called libuv). Node immediately moves on to serve the next user.
Once the operating system finishes reading the file, it places a "callback function" into the Event Queue. The Event Loop constantly spins, checking this queue. When the main thread is empty, it picks up the callback and returns the file data to the user.
The Phases of the Event Loop
The loop is not just a single circle; it has distinct phases executed in order:
- Timers: Executes callbacks scheduled by
setTimeout()andsetInterval(). - Pending Callbacks: Executes I/O callbacks deferred to the next loop iteration.
- Idle, Prepare: Used internally by Node.
- Poll: Retrieves new I/O events; executes I/O related callbacks (almost all of your code runs here).
- Check: Executes
setImmediate()callbacks. - Close Callbacks: Executes close events, e.g.,
socket.on('close', ...).
Don't Block the Event Loop!
Because there is only one main thread executing your JavaScript, if you write a massive, synchronous while loop, or do heavy synchronous cryptography (like bcrypt hashing without the async version), the entire server freezes. No other users can be served until that calculation finishes. Always use asynchronous methods for I/O operations.