Glossary

Event Loop

The event loop is the mechanism that allows JavaScript (a single-threaded language) to perform non-blocking asynchronous operations by managing the call stack, task queue, and microtask queue to execute code, collect events, and run queued tasks.

Explanation

JavaScript is single-threaded: only one piece of code runs at a time. Yet JavaScript handles async operations (network requests, timers, file I/O) without blocking. The event loop is how. The components: the call stack (where currently executing code lives — function calls push frames, returns pop them), the heap (where objects are allocated), the task queue / macrotask queue (where setTimeout callbacks, setInterval callbacks, and I/O callbacks wait), and the microtask queue (where Promise callbacks and queueMicrotask() callbacks wait — checked after each task, before the next macrotask). The event loop's algorithm: run the current synchronous code to completion (draining the call stack). Process ALL microtasks (Promise .then/.catch callbacks) until the microtask queue is empty. Process ONE macrotask (oldest setTimeout/setInterval callback). Repeat. This explains why Promise.resolve().then(() => console.log('microtask')) logs before setTimeout(() => console.log('macrotask'), 0) even though both are scheduled "later" — microtasks run before macrotasks. It explains why long-running synchronous code (a heavy computation in a loop) blocks the UI: while the call stack is busy, the event loop can't process user clicks or other events. Web Workers solve this by running heavy computation on a separate thread.

Code Example

javascript
// Event loop execution order

console.log('1 — synchronous');

setTimeout(() => console.log('5 — macrotask (setTimeout)'), 0);

Promise.resolve()
  .then(() => console.log('3 — microtask (Promise.then)'))
  .then(() => console.log('4 — microtask (chained .then)'));

console.log('2 — synchronous');

// Output order: 1, 2, 3, 4, 5

// Why the UI freezes: blocking the call stack
function blockingWork() {
  const end = Date.now() + 2000; // 2 second block
  while (Date.now() < end) {}    // busy-wait — blocks event loop
  console.log('Done'); // click events during this 2s are queued, not processed
}

// Fix: break work into chunks using setTimeout
function nonBlockingWork(items, processItem) {
  function processChunk(index) {
    const end = index + 100;
    for (let i = index; i < Math.min(end, items.length); i++) {
      processItem(items[i]);
    }
    if (end < items.length) {
      setTimeout(() => processChunk(end), 0); // yield to event loop
    }
  }
  processChunk(0);
}

Why It Matters for Engineers

The event loop is the foundation of JavaScript's entire concurrency model. Without understanding it, async/await timing feels magical and bugs are inexplicable. Stale state updates in React, setTimeout callbacks running after component unmount, Promise.all executing in the "wrong order" — these all make sense once you understand the event loop. It also explains a critical performance concern: any synchronous code that takes too long (> ~16ms to avoid dropping 60fps frames) blocks the event loop and freezes the UI. This is why computationally intensive tasks should be moved to Web Workers, and why React's concurrent mode was designed to allow rendering work to be interrupted and resumed.

Learn This In Practice

Go deeper with the full module on Beyond Vibe Code.

Programming Foundations → →