The event loop is how a single-threaded runtime like JavaScript handles many things in progress at once. Slow work (timers, network, files) is done outside your code; when it finishes, a callback waits in a queue, and the event loop runs it only when the call stack is empty.

How it works

One turn of the loop in a browser, as the HTML Standard describes it:

  1. Run the oldest task from a task queue until the call stack is empty.
  2. Run every microtask, including microtasks added while doing so, until the microtask queue is empty.
  3. If it is time to render: requestAnimationFrame callbacks, style, layout, paint.
  4. Repeat.

Node.js uses the same idea but with named phases (timers, poll for I/O, check for setImmediate, close callbacks), and runs process.nextTick callbacks and promise microtasks between callbacks.

Example

setTimeout(() => console.log('task'), 0);
Promise.resolve().then(() => console.log('microtask'));
console.log('sync');
// sync
// microtask
// task

Traps

  • setTimeout(fn, 0) is a minimum delay, not “now”.
  • Endless microtasks starve rendering; endless tasks do not.
  • Heavy synchronous code blocks everything. Move it to a Web Worker or split it into chunks.

Lesson: #1 · The event loop. Spec: HTML Standard: event loops.

Check yourself