The Node.js event loop is a single-threaded mechanism that handles asynchronous operations by continuously cycling through different phases to execute callbacks.
Event Loop Phases
The event loop has six main phases that execute in order:
- Timers - Executes callbacks scheduled by
setTimeout()
andsetInterval()
- Pending callbacks - Executes I/O callbacks deferred to the next loop iteration
- Idle, prepare - Only used internally
- Poll - Fetches new I/O events and executes I/O-related callbacks
- Check - Executes
setImmediate()
callbacks - Close callbacks - Executes close event callbacks (e.g.,
socket.on('close')
)
Call Stack and Callback Queue
- Call Stack: Executes synchronous code immediately. When empty, the event loop can process the next phase
- Callback Queue: Stores callbacks waiting to be executed. Different types of callbacks go to different queues with varying priorities
setTimeout vs Promise Execution
setTimeout: Callbacks go to the timer queue and execute during the timers phase of the next event loop iteration.
Promise: Uses the microtask queue (higher priority). Promise callbacks execute immediately after the current phase completes, before moving to the next event loop phase.
Key difference: Microtasks (Promises) have higher priority than macrotasks (setTimeout), so Promise callbacks always execute before timer callbacks, even if the timer delay is 0.
Example:
The event loop ensures non-blocking I/O by delegating operations to the system and processing their callbacks when complete, maintaining Node.js's asynchronous, single-threaded nature.