Understanding the Event Loop

1. Understanding Event Loop Phases

libuv Phases (per tick)

┌─► timers          (setTimeout, setInterval callbacks)
│   pending callbacks (deferred I/O)
│   idle, prepare    (internal)
│   poll             (retrieve new I/O events)
│   check            (setImmediate callbacks)
│   close callbacks  (e.g. socket.on("close"))
└─ (microtasks + nextTick run BETWEEN phases)
      

2. Understanding the Call Stack

ConceptDescription
Call stackLIFO of currently executing functions
Stack overflowRecursion too deep → RangeError
Single-threaded JSOne stack per isolate (worker = its own)

3. Understanding the Callback Queue

QueueSource
MacrotaskTimers, I/O, setImmediate, close
MicrotaskPromises, queueMicrotask
nextTickprocess.nextTick (drained before microtasks)

4. Using process.nextTick for Microtasks

Example

process.nextTick(() => console.log("a"));
Promise.resolve().then(() => console.log("b"));
console.log("c");
// c, a, b
Warning: Excessive nextTick chains can starve I/O.

5. Using setImmediate for Check Phase

APIPhase
setImmediate(fn)Check phase (after I/O)
setTimeout(fn, 0)Timers phase (≥1ms)

6. Understanding Microtasks vs Macrotasks

TypeWhen Drained
nextTick queueAfter current op, before microtasks
Microtask queue (Promises)After nextTick, before next phase
MacrotaskOne per phase iteration

7. Understanding Promise Resolution Timing

Example: Order

setTimeout(() => console.log("timeout"), 0);
setImmediate(() => console.log("immediate"));
Promise.resolve().then(() => console.log("promise"));
process.nextTick(() => console.log("nextTick"));
// nextTick, promise, then timeout/immediate (order between those varies)

8. Avoiding Event Loop Blocking

SourceFix
Sync FS (readFileSync)Use async or streams
JSON.parse on huge stringsStream parser
Heavy CPU (crypto, image)Worker threads
Tight loopsYield with setImmediate in batches

9. Monitoring Event Loop Lag

Example: perf_hooks monitor

import { monitorEventLoopDelay } from "node:perf_hooks";
const h = monitorEventLoopDelay({ resolution: 20 });
h.enable();
setInterval(() => console.log("p99 lag(ms):", h.percentile(99)/1e6), 1000);

10. Using Event Loop Utilities

APIUse
perf_hooks.monitorEventLoopDelayHistogram of lag
perf_hooks.eventLoopUtilization()Idle vs active
queueMicrotask(fn)Enqueue microtask
setImmediate.__promisify__Promise-based wait