What is the Event Loop in Node.js?
Learn how the Node.js event loop enables non-blocking I/O, its phases, microtasks vs macrotasks, and common interview pitfalls with code examples.
Expected Interview Answer
The event loop is the mechanism that lets single-threaded Node.js perform non-blocking I/O by offloading operations to the system and running their callbacks when the operation completes, instead of blocking the main thread while waiting.
Node's event loop cycles through fixed phases each tick: timers, pending callbacks, idle/prepare, poll, check, and close callbacks, with microtasks (Promises, process.nextTick) drained between every phase. When you call fs.readFile or make a network request, libuv hands the work to the OS or its thread pool, and Node keeps executing other code; once the operation finishes, its callback is queued into the appropriate phase. This is why Node can serve thousands of concurrent connections on one thread — it never waits idle on I/O. Understanding phase order matters for debugging timing bugs, like why setImmediate can fire before or after a setTimeout(fn, 0) depending on context.
- Enables high-concurrency I/O on a single thread
- Avoids thread-per-request overhead
- Keeps CPU free while waiting on network/disk
- Predictable phase ordering aids debugging
- Foundation for async/await and Promise scheduling
AI Mentor Explanation
The event loop is like an umpire who never stands idle between deliveries, sending a fielder to retrieve a ball while signalling for the next over to continue. The match keeps cycling through overs, breaks, and reviews in fixed order, and the fielder's return slots in exactly when the phase allows.
Node.js event loop phases
Timers
- setTimeout / setInterval callbacks due
Pending callbacks
- Deferred system-level callbacks
Poll
- Retrieve new I/O events
- Execute I/O callbacks
Check
- setImmediate callbacks
Close callbacks
- socket.on('close') etc.
Step-by-Step Explanation
Step 1
Call stack runs synchronous code
Node executes the current script's synchronous code to completion first.
Step 2
Async operations are offloaded
I/O, timers, and some crypto/fs work are handed to libuv or its thread pool.
Step 3
Microtasks drain first
After each callback, Node drains the microtask queue (Promises, process.nextTick) before moving on.
Step 4
Loop enters timers phase
Expired setTimeout/setInterval callbacks execute.
Step 5
Loop proceeds through poll and check
Poll handles I/O callbacks; check runs setImmediate callbacks.
Step 6
Cycle repeats
The loop keeps cycling through phases until no work remains, then the process exits.
What Interviewer Expects
- Explains Node is single-threaded but non-blocking via the event loop
- Names the major phases in rough order
- Distinguishes microtasks (Promises/nextTick) from macrotasks (timers/I/O)
- Understands the thread pool handles some blocking work (fs, crypto)
- Can reason about why setTimeout(fn,0) vs setImmediate ordering varies
Common Mistakes
- Saying Node is multi-threaded for all operations
- Claiming setTimeout(fn, 0) always fires before setImmediate
- Confusing the event loop with the call stack
- Ignoring that process.nextTick runs before other microtasks
- Assuming the event loop parallelizes CPU-bound JavaScript
Best Answer (HR Friendly)
“The event loop is what lets Node.js handle many requests at once without needing a thread per request. It keeps working on other tasks while waiting for things like file reads or database calls, then comes back to finish each one as it completes.”
Code Example
console.log('start');
setTimeout(() => console.log('timeout'), 0);
setImmediate(() => console.log('immediate'));
Promise.resolve().then(() => console.log('promise'));
process.nextTick(() => console.log('nextTick'));
console.log('end');
// Output:
// start
// end
// nextTick
// promise
// timeout (or immediate first, order varies outside I/O cycle)
// immediate (or timeout)Follow-up Questions
- What is the difference between process.nextTick and Promise microtasks?
- Why can setTimeout(fn, 0) and setImmediate fire in either order?
- How does the libuv thread pool relate to the event loop?
- What happens to the event loop when a synchronous function blocks for a long time?
- How would you detect event loop lag in a production Node app?
MCQ Practice
1. What does the event loop primarily enable in Node.js?
The event loop lets Node offload I/O and resume via callbacks, avoiding blocking on a single thread.
2. Which queue is drained before Node moves to the next event loop phase?
Microtasks, including process.nextTick and Promise callbacks, are drained between phases.
3. Which phase runs setImmediate callbacks?
setImmediate callbacks execute during the check phase of the event loop.
Flash Cards
What is the event loop? — The mechanism that lets single-threaded Node run non-blocking I/O by dispatching callbacks through fixed phases.
Name two event loop phases. — Timers and poll (also pending callbacks, check, close callbacks).
What runs between every phase? — Microtasks — process.nextTick queue, then the Promise microtask queue.
Who handles blocking I/O like file reads? — libuv's thread pool, which offloads the work and returns via callback.