Node.js — Advanced
The Node.js event loop, phase by phase
JavaScript's event loop concept (from this platform's JavaScript course) is a simplified, browser-oriented model. Node's actual event loop, implemented by libuv, runs through distinct, ordered phases each cycle — genuinely more granular detail than the browser model, and worth knowing precisely for both interviews and real debugging.
Microtasks — resolved Promise callbacks (.then) and process.nextTick — drain between every phase, not just once at the very end of a full cycle. process.nextTick callbacks run even before other microtasks (Promise callbacks), giving it the highest priority of anything in the loop — genuinely easy to overuse, since a recursive process.nextTick call can starve the event loop of ever reaching I/O.
This ordering — nextTick and Promise microtasks before any macrotask phase, setImmediate deterministically before setTimeout(fn, 0) specifically when called from inside an I/O callback — is a genuinely common, precise interview question, and it only makes sense once the phase model (not just "the event loop") is understood.
Clustering and worker threads: escaping the single-thread limit for CPU-bound work
Node's single JavaScript thread means a genuinely CPU-bound operation — image resizing, a large synchronous computation, heavy JSON parsing on a huge payload — blocks every request the process is handling for as long as it runs. There is no way around this with async/await alone; async/await only helps with I/O-bound waiting, not with actual computation.
worker_threads — run genuine parallel JavaScript in the same process, for CPU-bound work:
cluster — fork multiple Node processes, each with its own event loop and its own memory, to use multiple CPU cores for handling more concurrent requests (not for sharing state between them):
The distinction that matters: worker_threads is for CPU-bound work you want parallelized within one logical process; cluster (or a process manager like PM2) is for scaling request throughput across CPU cores by running multiple independent copies of your whole server. Reaching for cluster to solve a single slow synchronous function is the wrong tool — it multiplies capacity, but every individual worker process is still just as blockable by the same CPU-heavy code.
Memory leaks and profiling a Node process
Node's V8 heap is garbage-collected, but a leak still happens whenever references to objects are kept alive longer than intended — GC can't reclaim memory something still (even accidentally) references.
Diagnosing a suspected leak in practice:
The specific signal worth internalizing: healthy Node memory usage looks like a sawtooth (rises, GC runs, drops, repeats) when graphed over time. A leak looks like a sawtooth that never fully drops back down — each GC cycle reclaims some memory, but the floor keeps rising.
Performance under real concurrent load
Rising event-loop lag is the single most direct, Node-specific health signal available — it means something is either taking too long synchronously, or the process is genuinely saturated with more work than it can process. This is a more precise signal than CPU percentage alone: a process can show moderate CPU usage while still having real event-loop lag spikes from occasional blocking calls, which a coarse CPU-percentage graph averages away.
Load-testing consideration specific to Node: because a single Node process runs on one thread, load-testing a single instance measures the ceiling of one core, not the application's real production ceiling if it's deployed with cluster or multiple container replicas across cores. Test the actual deployed topology, not a bare node server.js on a laptop, when the goal is a realistic production-capacity number.
Try It (2 Minutes)
Run it with node blocking.js. The setTimeout was scheduled for 100ms, but notice it fires after the loop finishes, however long that actually took — the single event-loop thread was busy running the synchronous loop and literally could not check on the timer until that loop released the thread. This is the exact, concrete mechanism behind every "the API froze under load" incident this course's Production Example and Troubleshooting material describe.

