Back to Web Platform

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 Development

The concept you just explored is taught with full depth in the formal DURA curriculum.