Answer
After each synchronous script (or a single macrotask) finishes, the event loop first fully drains the microtask queue, then renders any pending UI updates, then picks up the next macrotask from the queue — repeating this cycle continuously.
// Simplified loop:
// while (true) {
// runOneMacrotask();
// drainAllMicrotasks();
// renderIfNeeded();
// }Real-world example Explaining why UI updates can appear to 'batch' after several synchronous state changes but before the next repaint.