Facebook Pixel

The Event Loop and Callbacks in JavaScript

The event loop runs callbacks when the stack is empty. Here is how it schedules callback execution.

The Event Loop and Callbacks in JavaScript

The event loop is the mechanism that runs callbacks when the call stack is empty. Understanding it explains all callback timing.

The Components

  • Call Stack: where JS code runs, one at a time.
  • Web APIs: browser-provided async operations (setTimeout, fetch, DOM events).
  • Macrotask Queue: callbacks from setTimeout, setInterval, I/O, events.
  • Microtask Queue: callbacks from Promise.then, queueMicrotask.
  • Event Loop: moves callbacks from queues to the stack.

How a Callback Gets Called

  1. You call setTimeout(cb, 1000).
  2. The Web API starts a timer for 1000ms.
  3. The engine continues running synchronous code.
  4. When the timer fires, cb goes to the macrotask queue.
  5. The event loop checks: is the stack empty? Are microtasks done?
  6. If yes, cb is moved to the stack and runs.

Order of Execution

console.log("sync"); setTimeout(() => console.log("timeout"), 0); Promise.resolve().then(() => console.log("promise")); `` **Output**: `sync, promise, timeout`. 1. `sync` runs on the stack. 2. `timeout` callback goes to the macrotask queue. 3. `promise` callback goes to the microtask queue. 4. Stack is empty. Drain microtasks: `promise` runs. 5. Take one macrotask: `timeout` runs. ### Microtasks vs Macrotasks - **Microtasks** (promise callbacks, `queueMicrotask`): run after the current task, before the next macrotask. The event loop drains all microtasks before any macrotask. - **Macrotasks** (`setTimeout`, `setInterval`, I/O, events): run one at a time, with microtasks drained after each. ### Blocking Delays Everything ```js setTimeout(() => console.log("timer"), 1000); function block() { const start = Date.now(); while (Date.now() - start < 3000) {} // 3 seconds } block(); `` **Output**: `timer` (after 3 seconds). The timer fired at 1 second, but the callback was queued. The event loop could not run it until `block` returned. ### The Takeaway The event loop runs callbacks when the call stack is empty and all microtasks are done. Microtasks (promises) always run before macrotasks (timers, events). Blocking the stack delays all queued callbacks. Understanding this order explains all callback timing in JavaScript.

When the call stack is empty, the event loop drains all microtasks (promise callbacks, queueMicrotask), then takes one macrotask (setTimeout, events). This repeats. Callbacks only run when the stack is empty.

Because promise callbacks go to the microtask queue, which the event loop drains completely before taking any macrotask from the macrotask queue where setTimeout callbacks live. Microtasks always run first.

Yes. If synchronous code is still running, the callbacks stay in the queue. The event loop cannot move them to the stack until it is empty. A 3-second blocking function delays all queued callbacks by 3 seconds.

Microtasks (promise callbacks, queueMicrotask) run after the current task and before the next macrotask. The event loop drains all microtasks before any macrotask. Macrotasks (setTimeout, events) run one at a time with microtasks drained after each.

Sync code runs first on the call stack. When the stack is empty, the event loop drains all microtasks. Then it takes one macrotask. Then drains microtasks again. This repeats: sync, microtasks, one macrotask, microtasks, one macrotask, ...

Ready to master React completely?

Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.

Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.