The Event Loop: Microtasks, Macrotasks, and Rendering
The event loop has two queues and they do not have equal priority. Here is the order that explains every timing puzzle. JavaScript is single-threaded, yet it handles timers, network responses, user input, and animations without freezing. The event loop is the scheduler that makes this work, and understanding its two-queue structure resolves every timing puzzle I have ever encountered. The model is simple, but the implications are not. The Call Stack Comes First The call stack executes synchronous code. While the stack is non-empty, the event loop cannot do anything else. This is why a long synchronous computation blocks everything: timers fire late, clicks go unhandled, and the page freezes. The first principle of responsive JavaScript is to keep the call stack empty by yielding back to the loop frequently. Macrotasks and Microtasks There are two queues. The macrotask queue holds callbacks from setTimeout, setInterval, I/O, and DOM events. The microtask queue holds promise callbacks and queueMicrotask calls. The critical rule is that after every macrotask, the engine drains the entire microtask queue before running the next macrotask. Microtasks always preempt macrotasks. console.log('A'); setTimeout(() => console.log('B'), 0); Promise.resolve().then(() => console.log('C')); console.log('D');…