Frontend engineer path · The language · Topic 3 of 17

The event loop

Not started

The engine runs one task to completion, then empties the microtask queue, then (in a browser) may update the screen, and only then picks the next task. Timers, clicks and network replies don't interrupt your code; they wait in a queue for the stack to be empty.

Why it matters: It decides the order your logs appear in, and why one slow function makes the whole page stop responding.

  1. 1One thing at a time

    There is one call stack. Whatever is on it runs to the end; nothing else can cut in.

  2. 2Waiting happens elsewhere

    Timers, network replies and clicks are tracked outside your code. When one is ready, its callback joins the task queue.

  3. 3Microtasks jump the line

    After every task, the loop runs every queued microtask (promise callbacks, code after an await, queueMicrotask), including ones added on the way.

  4. 4Then the next task

    A browser may now update the screen. Then the loop takes the oldest ready task and starts again.

1

Watch it run

Pick a snippet, then play it or step through. Every step says what just happened.

console.log("start");setTimeout(() => {  console.log("timeout");}, 0);console.log("end");

Call stack

What is running right now

empty

Web APIs / timers

Waiting outside JavaScript

empty

Task queue

Macrotasks: one per turn

empty

Microtask queue

Drained fully after each task

empty

Console output0 lines

    Step 0 of 8

    Nothing has run yet. The stack is empty and both queues are empty.

    2

    Try it yourself

    Change the code, predict the order, then run it for real in your browser.

    ⌘/Ctrl + Enter
    OutputNot run yet

    Press Run to see what your code prints, in order.

    Runs in this browser, in an isolated frame with no access to this page. console.log, info, warn and error are shown; code runs as a classic script, so use an async function for await.

    3

    Check yourself

    3 questions. Get them all right to finish this topic.

    1. 1.What is printed first?
      setTimeout(() => console.log("a"), 0);Promise.resolve().then(() => console.log("b"));console.log("c");
    2. 2.In what order are the letters printed?
      async function f() {  console.log("x");  await undefined;  console.log("y");}f();console.log("z");
    3. 3.A microtask queues another microtask. What prints last?
      setTimeout(() => console.log("timer"), 0);Promise.resolve().then(() => {  console.log("p1");  Promise.resolve().then(() => console.log("p2"));});console.log("sync");

    0 of 3 right so far. Get all three to finish this topic.

    Browser or Node: what changes?

    • All three snippets print in the same order in Chrome and in Node 22, whether Node runs them as CommonJS or as an ES module. The task-then-microtasks rule is the same in both.
    • Node has no screen to paint. Its loop goes through phases instead (timers, I/O polling, setImmediate callbacks, close callbacks), covered in Node's event loop.
    • Node adds process.nextTick, whose queue runs before promise microtasks. Browsers have no equivalent.
    • A 0 ms timer is never instant. Node treats it as 1 ms; browsers clamp deeply nested timers to at least 4 ms and slow timers down in background tabs.