Event loop · Microtasks · rAF
Event Loop
Schedule setTimeout, Promise.then, and requestAnimationFrame. Watch the loop drain microtasks before macrotasks, and watch a sync block freeze the paint counter.
JavaScript runs one thing at a time. The event loop is the scheduler that decides which queued thing runs next — and the order it picks is the difference between a smooth UI and a janky one. This demo simulates the loop one tick at a time: schedule the four kinds of work, click Step, and watch the call stack pull from the microtask queue, the macrotask queue, and the animation-frame queue in the order the spec says it must.
Explore the activity to earn its passport stamp. Stamps record exploration, not mastery.
What’s happening under the hood
- ›Microtasks (Promise.then, queueMicrotask, MutationObserver) drain to EXHAUSTION between every macrotask. The loop will never take the next setTimeout while a single microtask is still queued — which is why a deep .then chain can postpone macrotasks indefinitely. Queue a `.then chain ×5` and watch the setTimeout sit there waiting.
- ›requestAnimationFrame is wired to RENDER, not to the microtask queue. The browser runs rAF callbacks immediately before committing the next frame — which is what makes rAF the right hook for animation work (it runs at the display's pace) and the wrong hook for general async coordination.
- ›A synchronous CPU loop blocks EVERYTHING: no microtasks drain, no rAFs fire, no paint commits. This is the pathology behind every FE perf war story — a long for-loop, a sync JSON.parse on a big blob, a heavy markdown render — and the original argument for moving work off the main thread (workers, idle callbacks, streaming, time-slicing).
Dig deeper
Phase 2 · Web DevelopmentThe concept you just explored is taught with full depth in the formal DURA curriculum.