1 min read 258 words Updated Sep 24, 2026 Created Sep 24, 2026
#JavaScript#VanillaJS

Event Loop

JavaScript is single-threaded — it can only execute one statement at a time. The event loop is the mechanism that makes non-blocking async behaviour possible.

It continuously checks: is the call stack empty? If yes, it picks the next waiting callback and pushes it onto the stack.

The moving parts

ComponentRole
Call StackWhere your code runs. Functions are pushed on, popped off when they return.
Web APIs / Node APIsBrowser or Node provide these (setTimeout, fetch, fs.readFile, etc.). They do work outside the JS engine.
Callback Queue (Task Queue)When a Web/Node API finishes, its callback goes here to wait.
Microtask QueuePromise .then() / .catch() / .finally() handlers go here. Always drained before the next task queue item.

Execution order example

console.log('1 — sync')

setTimeout(() => {
  console.log('2 — macrotask (setTimeout)')
}, 0)

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

console.log('4 — sync')

Output:

1 — sync
4 — sync
3 — microtask (Promise)
2 — macrotask (setTimeout)
Microtasks always run first

After every synchronous chunk, the engine drains the entire microtask queue before picking a single macrotask.

Blocking the call stack blocks everything

A long-running while loop or heavy computation stalls the event loop — no callbacks, no renders, no I/O. Offload heavy work to Workers.

Related

Asynchronous — Promises & async/await
Callbacks — the original async pattern