Node.js › Event Loop & Non-blocking IO
How does the V8 JavaScript engine's microtask queue interact with the Node.js event loop's macrotask phases, and why does this occasionally surprise developers?
AdvancedAnswer
Promise-based microtasks are actually managed by the V8 engine itself, independently of Node's own event loop implementation (which handles macrotasks like timers and I/O) -- but Node.js ensures the microtask queue is fully drained after each individual callback completes (not just once per full event loop iteration), meaning a chain of many resolved promises can, in principle, indefinitely delay macrotasks like timers from ever running if new microtasks keep being scheduled from within other microtasks, a subtle 'microtask starvation' scenario that can surprise developers expecting timers to fire predictably.
function scheduleForever() {
Promise.resolve().then(scheduleForever); // an infinite chain of microtasks
}
scheduleForever();
setTimeout(() => console.log('This may never fire!'), 100); // starved by the microtask chain aboveReal-world example A developer debugging why a setTimeout callback never fired despite a generous delay eventually traces it to an accidental infinite chain of chained .then() calls recursively scheduling more microtasks, which as V8-level microtasks are always fully drained before the event loop can proceed to the timers phase.