Async Era
ES2017+2017 – 2019`async`/`await` made the microtask queue an everyday concern. Asynchronous code finally reads top-to-bottom while still yielding to the loop at each await.
Microtasks drain completely before the next macrotask. A promise chain scheduled inside a timer still finishes before the following timer fires.
setTimeout(() => {
console.log("timer 1");
Promise.resolve().then(() => console.log(" micro inside timer 1"));
}, 0);
setTimeout(() => console.log("timer 2"), 0);
Promise.resolve().then(() => console.log("micro before any timer"));
console.log("sync");| V8 | Ships no event loop at all. It exposes a microtask queue and expects the embedder to pump it. |
|---|---|
| Node.js | libuv phases: timers → pending → poll → check (`setImmediate`) → close. `setImmediate` fires after I/O, `setTimeout(fn, 0)` before it. |
| Deno | Rust + Tokio. No `setImmediate` in the native API surface (only via the Node compatibility layer); web timers are the primitive. |
| Bun | Custom loop on JavaScriptCore. Implements Node's `setImmediate` for compatibility; timer latency is generally lower under load. |