# Event Loop — Part 1: The Mechanism

## 1. The Problem the Event Loop Solves

JavaScript has one call stack and runs on one thread. Yet it can handle timers, network responses, and user input without freezing. The **event loop** is the mechanism that makes this possible — it coordinates the call stack, a set of task queues, and the browser/Node APIs that handle async work outside of JavaScript itself.

## 2. The Four Pieces

![Call stack hands off async work to Web/Node APIs, which feed the macrotask and microtask queues that the event loop drains back into the stack](diagrams/01-event-loop-overview.svg)

```
┌─────────────┐     ┌───────────────────────────┐
│  Call Stack   │     │  Web APIs / Node APIs       │
│  (runs code)  │     │  (setTimeout, fetch, fs...)  │
└──────┬───────┘     └──────────────┬───────────────┘
        │                              │ (when ready)
        │                              ▼
        │                    ┌───────────────────┐
        │                    │  Callback / Task    │
        │                    │  Queues (macro/micro)│
        │                    └─────────┬───────────┘
        ▲                              │
        └──────────── Event Loop ◄─────┘
        (moves queued callbacks onto the stack
          ONLY when the stack is completely empty)
```

1. **Call Stack** — where currently-executing synchronous code lives (see the Call Stack topic).
2. **Web/Node APIs** — the runtime environment (not JavaScript itself) that handles timers, I/O, and network requests in the background.
3. **Task Queues** — where completed async callbacks wait their turn (split into microtasks and macrotasks — full detail in the next topic).
4. **The Event Loop** — a continuously running process that checks: "is the call stack empty? If so, take the next callback from the queue and push it onto the stack."

## 3. Walking Through an Example

```js
console.log("1");

setTimeout(() => console.log("2"), 0);

console.log("3");
```

Step by step:
1. `console.log("1")` runs synchronously on the call stack, prints `1`.
2. `setTimeout(...)` is handed off to the Web/Node API layer, which starts a 0ms timer. The call stack is NOT blocked waiting for it.
3. `console.log("3")` runs synchronously, prints `3`.
4. The synchronous script finishes; the call stack is now empty.
5. The timer (already expired) has placed its callback in the macrotask queue.
6. The event loop sees the empty stack, takes the callback from the queue, pushes it onto the stack.
7. It runs, prints `2`.

Result: `1`, `3`, `2` — never `1`, `2`, `3`, no matter how short the timeout delay is.

## 4. The Golden Rule

**The event loop never interrupts running synchronous code.** It only ever moves a queued callback onto the stack when the stack is completely empty. This is why a long synchronous operation (see the Call Stack topic) blocks every pending timer and network response, no matter how "urgent" they are.

## 5. Why `setTimeout(fn, 0)` Isn't Instant

Even with a 0ms delay, the callback still has to:
1. Wait for the timer to be registered by the Web/Node API layer.
2. Wait for the CURRENT synchronous code to finish completely.
3. Wait for the event loop to notice the stack is empty and pull it off the queue.

None of that is instantaneous, and step 2 alone can take arbitrarily long if the current script keeps running.

Continue to `js_event_loop_theory_2.md` for how microtasks and macrotasks interact within the loop.
