Skip to content

JavaScript Tutorial Asynchronous JavaScript

The JavaScript Event Loop (Simply Explained)

Lesson 149 of 258 2 min read By Deepak Paswan Updated Oct 4, 2026

JavaScript runs one thing at a time, yet it handles clicks, timers and network replies. The event loop is how.

The pieces

  • Call stack: where the code that is running right now lives. One thing at a time.
  • Web APIs: the browser’s own machinery (timers, network, events) that works outside your code.
  • Task queue: callbacks that are ready to run (timers, events), waiting for the stack to be empty.
  • Microtask queue: a higher-priority queue for promise handlers and queueMicrotask.

The event loop does this forever:

  1. Run the current code until the call stack is empty.
  2. Run all microtasks.
  3. Take the next task from the task queue and run it.
  4. (Let the browser repaint if needed.) Repeat.

A puzzle

What order does this print?

script.js
JS
console.log("1. script start");

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

Promise.resolve().then(() => console.log("3. promise"));

queueMicrotask(() => console.log("4. microtask"));

console.log("2. script end");

The answer: 1, 2, 3, 4, 5. Here is why:

  1. script start and script end are normal code, so they run first, in order.
  2. The setTimeout callback goes to the task queue.
  3. The promise handler and the microtask go to the microtask queue.
  4. When the script finishes, the loop runs all microtasks (3 and 4) before the next task (5).

So even with a delay of 0, a timer runs after every pending promise handler.

What this means in practice

  • Promise code (then, await continuation) runs sooner than timers.
  • A long synchronous loop or heavy calculation blocks everything, including clicks and screen updates, because the loop cannot take the next task.
  • An endless chain of microtasks can starve the page, because it never gets to the next task.

await in the picture

Code after an await continues as a microtask once the promise settles.

script.js
JS
async function demo() {
  console.log("A");
  await null;
  console.log("C");
}

demo();
console.log("B");
// the order is A, B, C

Why the page freezes

script.js
JS
button.addEventListener("click", () => {
  while (true) {}      // nothing else can ever run: the stack never empties
});

If your code runs a long job, the page cannot respond. Split the work into small pieces, use a Web Worker (Web Workers), or find a faster way.

You do not need to memorise it

Remember three things: synchronous code first, then promises (microtasks), then timers and events (tasks), and never block the stack.

info
It is a simplification
Real browsers have several task queues and rendering steps in between, but this model explains almost everything you will see day to day.