The JavaScript event loop: microtasks before timers

Read the explanation
What if

One thread runs the whole script first. Then every microtask (the promise), and only then the next task (the timeout).

Predict first

The script logs, sets a 0 ms timeout, adds a promise callback, and logs again. In what order do the four lines print?

0123456JS thread: log script startslogJS thread: setTimeout(…, 0)setTimeoutJS thread: Promise.then(…)thenJS thread: log script endslogJS thread: promise callbackpromiseJS thread: timeout callbacktimeouttimeout callback, queuedmicrotask queue: promise callback, queuedqueued

Tap any block to see what that thread is doing.

  • Running
  • Waiting / parked
Step 1/5

One thread runs all the JavaScript. The script runs to the end before anything else gets a turn.

1console.log("script starts");2setTimeout(() => console.log("timeout"), 0); // a task: waits for the script and every microtask3Promise.resolve().then(() => console.log("promise")); // a microtask: runs as soon as the script ends4console.log("script ends");

Explanation

What just happened

One thread runs all the JavaScript, and nothing interrupts the running script. setTimeout(…, 0) queued its callback as a task; Promise.then queued its callback as a microtask. When the script ended, the event loop first ran every microtask (promise), then took the next task (timeout).

Try the what-if switch

The rule

Run the current task to the end. Then run all microtasks, including any they queue. Then take one task. Repeat.

Watch out

“0 ms” is a minimum, not a promise. A timer callback always waits for the script and every microtask in front of it.

Common questions

Why does a promise run before setTimeout 0?

Promise callbacks are microtasks; timer callbacks are tasks. After the current script, the event loop runs every queued microtask before it takes the next task, so the promise wins even though the timer was set first.

Is the code after await a microtask?

Yes. An async function runs until its first await, then returns. The rest is queued as a microtask, so it runs right after the current script, before any waiting timer.

Can microtasks block timers?

Yes. If each microtask queues another, the queue never empties and timers wait. In our test a 0 ms timeout waited for a million microtasks.

Verified: this timeline matches a real program, checked in CI on Node.js 22 and 24. How we verify. Unclear or wrong? Tell us