Home/Labs/Event Loop Queue Drain
All 280 Labs
INTERACTIVE LAB⏳

Event Loop Lab (Interactive)

Step a Node-style loop tick-by-tick and drop in a 200ms sync task to watch queue lag spike. An executable model of call stack, microtask queue, macrotask queue, and libuv timers showing exact callback ordering and event loop lag.

Event Loop: Microtasks, Macrotasks & Blocking

Step a Node.js-style loop tick by tick — then drop a synchronous crypto task on the stack and watch every timer starve.

Synchronous phase: frame 1/5

Call Stack (single V8 thread)

↳ main()

libuv / kernel (epoll, thread pool)

no pending async handles

Microtask Queue — drains COMPLETELY per tick

empty

Macrotask Queue — ONE per tick (timers, I/O, setImmediate)

empty

STDOUT — execution order0 lines

Press Next Tick to run the loop.

Simulated clock
0.0 ms
Microtasks done
0
Event loop lag (max)
0.0 ms
Loop state
RUNNING

Order proof: microtasks (3, then nested 7) run before the next macrotask (4); the 200ms sync hog pushes every timer callback behind it, producing 0ms of loop lag — in production that means health-check timeouts and CrashLoopBackOff. Offload CPU work to worker_threads or a task queue.

How It Works Under the Hood

An event loop interleaves independent tasks on one thread: synchronous frames run first, then the microtask queue drains completely (promises, nextTick), then exactly one macrotask (timers, I/O callbacks) runs. Network I/O rides the kernel (epoll) while file/DNS/crypto work uses libuv’s 4-thread pool. Because everything shares the one thread, any synchronous CPU hog stalls every connection — timers scheduled at 0ms fire 200ms late.

Core Architectural Principles

  • Microtasks drain to empty between every macrotask — nested promises run before the next timer.
  • One macrotask executes per loop tick, so timers/I/O callbacks take turns, never concurrently.
  • Loop lag equals scheduled-fire time minus actual execution time under a synchronous CPU hog.
Interview Round Script

Answer ordering puzzles by naming the queues: "stack empties, then all microtasks, then one macrotask." Then design-taste it: "Node doubles PayPal’s requests per box for I/O-bound APIs, but bcrypt.hashSync in a request handler fails health checks — offload to worker_threads or BullMQ."

Key Trade-Offs

Single-threaded loops give lock-free simplicity and massive I/O concurrency, but one blocking handler degrades every connection behind it.

Related Curriculum Chapter

Event Loops & Non-Blocking Execution Models

Read Full Chapter Blueprint

Explore More Interactive Labs

View All 280 Labs