An illustrated course · free to learn
See exactly how the JavaScript event loop runs your code.
Step through the event loop one animated figure at a time — explained simply, for developers, or straight from the spec. Then paste your own code and watch it run.
1console.log('start');2 3setTimeout(() => {4 console.log('timeout');5}, 0);6 7Promise.resolve().then(() => {8 console.log('promise');9});10 11console.log('end');The script starts executing top to bottom on the call stack. console.log("start") runs synchronously and prints right away.
Call stack
Web APIs — browser land
The event loop — is the call stack empty? → drain the microtask queue first → then take one callback.
Microtask queue — priority
Callback queue
Console
Fig. — the classic: Promise vs setTimeout, running on a loop · step 1 of 9
One figure. Three voices.
The animation never changes — the explanation does. Switch anytime with the toggle above, or keys 1 · 2 · 3.
Explain simply
One chef, one kitchen, a VIP line. The whole loop as a story a curious kid can follow.
Developer
Call stack, task queue, microtasks — the practical model behind every "why is this async?" bug.
Under the hood
Task sources, microtask checkpoints, render opportunities — straight from the HTML spec.
The event loop, in words
What is the JavaScript event loop?
JavaScript runs on a single thread — it can do one thing at a time. The event loop is the runtime's scheduler: it executes the current script on the call stack, then drains the microtask queue (promise callbacks), then picks the next task (timers, events) from the task queue — over and over. Watching it run, tick by tick, is the fastest way to make the model stick.
Why does setTimeout(0) run after a promise?
Because zero milliseconds means "not before 0ms", not "now". When the stack empties, the runtime first drains every microtask — and each .then() callback is a microtask — before it takes even one timer callback from the task queue. So a resolved promise always beats setTimeout(fn, 0). Watch it happen →
What's the difference between tasks and microtasks?
Both are queued callbacks, but microtasks (promise reactions, queueMicrotask, the resume of an await) get a VIP lane: the queue drains completely after the current script, before any task — or the next render. Tasks (timeouts, events, I/O) wait their turn one at a time. Starve the loop with an endless stream of microtasks and timers never eat — see the starvation scene →
Can I visualize my own code?
Yes — paste any snippet using console.log, setTimeout, promises, queueMicrotask, or async/await into the playground and step through it on the same animated call stack, queues, and Web APIs — forward, backward, at any speed.