Script Valley
JavaScript: The Complete Language
Asynchronous JavaScriptLesson 4.1

The JavaScript event loop explained simply

event loop, call stack, web APIs, callback queue, microtask queue, task queue, setTimeout behavior, synchronous vs asynchronous, non-blocking I/O

How JavaScript Handles Async Without Threads

JavaScript is single-threaded but handles async operations efficiently through the event loop. Understanding it is essential for predicting execution order โ€” one of the most-asked JavaScript interview topics and a source of genuine runtime bugs.

The Sequence

  1. Synchronous code runs on the call stack to completion.

  2. Async operations (timers, fetch, I/O) are handed off to browser or Node.js Web APIs.

  3. When those complete, their callbacks are pushed into a queue.

  4. The event loop checks: is the stack empty? If yes, it moves the next queued callback onto the stack.

console.log("1");

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

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

console.log("4");

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

Microtask Queue vs Callback Queue

Promise callbacks go into the microtask queue, which is fully drained between each macrotask (setTimeout, setInterval). This is why Promise .then callbacks always run before setTimeout callbacks โ€” even with a 0ms delay. The microtask queue must be empty before the event loop picks the next macrotask.

Why This Matters in Practice

Long synchronous operations block the entire call stack โ€” no UI updates, no event handling, nothing. Heavy computation must be chunked or offloaded to Web Workers to keep applications responsive.

Up next

Promises in JavaScript: how to create and consume them

Sign in to track progress

The JavaScript event loop explained simply โ€” Asynchronous JavaScript โ€” JavaScript: The Complete Language โ€” Script Valley โ€” Script Valley