ON THIS PAGE
“JavaScript is single-threaded” is true in the same way that “a restaurant has one cashier” is true: useful, incomplete, and a terrible model of the whole operation.
Several queues, one turn
The browser coordinates task sources, microtasks, rendering opportunities, timers, and native subsystems. The event loop is the scheduling rule that decides when each kind of work gets its turn.
console.log("A");
setTimeout(() => console.log("B"), 0);
Promise.resolve().then(() => console.log("C"));
console.log("D");
// A, D, C, BMicrotasks can starve the page
After a task completes, the runtime drains the microtask queue before the browser gets another rendering opportunity. A microtask that continually schedules another microtask can keep the page from painting.
Yield with intent
Use a task boundary when the browser needs a chance to handle input or render. Use a microtask when a small piece of work must run before that next boundary.
The debugging habit
When order matters, label the kind of work—not merely the callback. “This runs later” is not precise enough. Ask which queue owns it and what must drain first.