跳到主要内容

Event Loop

Event loop = JavaScript's async mechanism


What is the Event Loop?

"Single thread + async callbacks"

The event loop is JavaScript's mechanism for handling asynchronous operations in a single-threaded environment.

"The event loop is JavaScript's concurrency model that enables asynchronous operations despite being single-threaded, using a call stack, callback queue, and event loop."


JavaScript Runtime Components

Call Stack · Web APIs · Callback Queue · Event Loop

┌─────────────┐
│ Call Stack │ ← Synchronous code
└─────────────┘

┌─────────────┐
│ Web APIs │ ← setTimeout, fetch, DOM
└─────────────┘

┌─────────────┐
│ Callback │ ← Ready callbacks
│ Queue │
└─────────────┘

┌─────────────┐
│ Event Loop │ ← Moves callbacks to stack
└─────────────┘

"The event loop coordinates the call stack, Web APIs, and callback queue to handle asynchronous operations."


How It Works

Stack → APIs → Queue → Loop

  1. Call Stack: Executes synchronous code
  2. Web APIs: Handle async operations (setTimeout, fetch)
  3. Callback Queue: Holds ready callbacks
  4. Event Loop: Moves callbacks from queue to stack when stack is empty

"The event loop continuously checks if the call stack is empty, then moves callbacks from the queue to the stack."


Example Flow

Synchronous first, async later

console.log("1");

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

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

console.log("4");

// Output: 1, 4, 3, 2

Why?

  • 1 and 4 are synchronous
  • 3 is microtask (Promise)
  • 2 is macrotask (setTimeout)

"Synchronous code runs first, then microtasks (Promises), then macrotasks (setTimeout)."


Microtasks vs Macrotasks

Microtasks > Macrotasks

TypeExamplesPriority
MicrotasksPromises, queueMicrotaskHigh
MacrotaskssetTimeout, setIntervalLow

"Microtasks (Promises) have higher priority than macrotasks (setTimeout) in the event loop."


Call Stack

LIFO - Last In, First Out

  • Executes code synchronously
  • One function at a time
  • Blocks when busy
  • Stack overflow if too deep

"The call stack executes code synchronously in a LIFO manner, blocking when processing."


Blocking the Event Loop

Heavy computation blocks everything

// ❌ Blocks event loop
for (let i = 0; i < 1000000000; i++) {
// heavy computation
}

// ✅ Use Web Workers or break up work

"Heavy synchronous operations block the event loop, preventing other code from running."


setTimeout(0)

Defer to next event loop cycle

console.log("1");
setTimeout(() => console.log("2"), 0);
console.log("3");
// Output: 1, 3, 2

Even with 0ms delay, setTimeout runs after current execution.

"setTimeout with 0ms defers execution to the next event loop cycle, after current code completes."


9️⃣ Promise Queue

Promises = microtask queue

Promise.resolve().then(() => console.log("microtask"));
setTimeout(() => console.log("macrotask"), 0);
// microtask runs first

"Promises are added to the microtask queue, which has priority over the macrotask queue."


Visual Example

Order matters

console.log("Start");

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

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

console.log("End");

// Output: Start, End, Promise 1, Promise 2, Timeout

"The event loop enables asynchronous JavaScript in a single-threaded environment. It uses a call stack for synchronous code, Web APIs for async operations, and callback queues. The event loop moves callbacks from queues to the stack when the stack is empty. Microtasks (Promises) have higher priority than macrotasks (setTimeout). Synchronous code always runs first, then microtasks, then macrotasks."


🧠 Ultra-Short Cheat Sheet

Single-threaded
Call stack (synchronous)
Web APIs (async)
Callback queue
Event loop (coordinator)
Microtasks > Macrotasks
Synchronous first