What you'll be able to do

By the end of this page you should be able to explain why setTimeout(fn, 0) is not instant, predict a simple microtask vs macrotask log order, and connect the event loop to async code you already write (fetch, Promise.then, async/await).

Previous post: execution context and call stack.

Who this is for

  • People who logged "timeout" before "sync" and thought the timer was broken
  • Beginners who finished the stack post and asked "what runs next?"
  • Anyone who saw Promise.then beat setTimeout(0) in a quiz and wanted a calm explanation

You can skip this if task order already feels predictable. This closes Phase 9 — mental models.

Stack first, then queues

While your synchronous code runs, the call stack is busy — callbacks from timers or clicks wait their turn.

console.log("A");
setTimeout(function () {
  console.log("B");
}, 0);
console.log("C");
// A, C, B

Scenario A — zero delay is not zero work. setTimeout(..., 0) means "queue this macrotask after the current stack clears," not "run now."

Scenario B — long sync loop. If you block the stack for three seconds, timers and clicks wait — the page feels frozen.

The rule: finish current JS on the stack; then the event loop picks the next task.

Macrotasks vs microtasks (practical names)

Macrotasks (task queue): setTimeout, setInterval, I/O callbacks, UI events — broad bucket you can call "later tasks."

Microtasks: Promise.then, queueMicrotask, async/await continuations after a await — run after the current stack, before the next macrotask.

console.log("1");
setTimeout(function () {
  console.log("2 timeout");
}, 0);
Promise.resolve().then(function () {
  console.log("3 microtask");
});
console.log("4");
// 1, 4, 3 microtask, 2 timeout

Scenario A — interview log order. Sync first, microtasks drain, then macrotasks.

Scenario B — fetch + then + setTimeout. Response then is microtask; timer is macrotask — UI updates often follow this pattern.

You do not need every browser internal name — remember promises before timers when both are queued during the same synchronous turn.

Why this matters for UI

button.addEventListener("click", function () {
  heavySyncWork(); // blocks paint and other callbacks
});

Scenario A — click feels laggy. Stack never clears until heavySyncWork finishes.

Scenario B — split work. queueMicrotask or setTimeout(0) can yield — but the real fix for big jobs is smaller chunks or a worker, not endless setTimeout hacks.

A tiny practice file

<!DOCTYPE html>
<html>
  <body>
    <button id="go">Run loop demo</button>
    <pre id="out"></pre>
    <script>
      const out = document.getElementById("out");
      function log(msg) {
        out.textContent += msg + "\n";
      }
      document.getElementById("go").addEventListener("click", function () {
        out.textContent = "";
        log("sync start");
        setTimeout(function () {
          log("macrotask timeout");
        }, 0);
        Promise.resolve().then(function () {
          log("microtask promise");
        });
        log("sync end");
      });
    </script>
  </body>
</html>

Click — order should be sync start, sync end, microtask promise, macrotask timeout.

Mistakes I see a lot

1. Expecting setTimeout(0) to run before the next line of sync code.

2. Assuming async/await is a new thread. It still schedules continuations as microtasks on the same thread.

3. Chaining infinite microtasks and wondering why the page never paints. Drain the stack, yes — but do not recurse microtasks forever.

4. Over-studying loop diagrams before running one log script. Type the four-line example once; the order sticks.

What to try before the next post

  1. Predict then log the 1/4/3/2 example; change to nested then and two timeouts.
  2. Watch the Network tab: when does then run relative to load events?
  3. Build the tiny HTML file.

This closes Phase 9 — mental models. Next we begin Phase 10 — useful deeper JS: modules — named, default, and dynamic import.

Try this next outside the series

These mental models become more useful when you can point at a real framework problem they explain.