JS Guide
HomeQuestionsTopicsCompaniesResources
BookmarksSearch

Built for developers preparing for JavaScript, React & TypeScript interviews.

ResourcesQuestionsSupport
HomeQuestionsSearchProgress
HomeTopicsjavascriptEvent Loop & Runtime
PrevNext
javascript
intermediate
15 min read

Event Loop & Runtime

async
call-stack
event-loop
macrotasks
microtasks
performance
raf
runtime

JavaScript is single-threaded with one call stack — the event loop enables async behavior by processing microtasks (promises) before macrotasks (setTimeout) between each cycle of the call stack.

Key Points

1Single-Threaded Model

JavaScript has one call stack executing one piece of code at a time — async behavior is achieved through the event loop, not parallel execution.

2Call Stack and Web APIs

Synchronous code runs on the call stack; async operations (timers, fetch, events) are handled by browser/Node APIs and their callbacks are queued.

3Microtasks vs Macrotasks

Microtasks (promises, queueMicrotask) have priority over macrotasks (setTimeout, I/O). The entire microtask queue drains before the next macrotask runs.

4Event Loop Cycle

Execute call stack → drain all microtasks → render if needed → pick one macrotask → repeat. This cycle runs continuously.

5requestAnimationFrame

Runs after microtasks but before paint, synchronized with display refresh rate — the correct API for visual animations.

What You'll Learn

  • Explain the JavaScript event loop and how it enables asynchronous behavior
  • Predict execution order of synchronous code, promises, and setTimeout
  • Know the difference between microtasks and macrotasks and their priority

Deep Dive

JavaScript runs on a single thread with one call stack, yet it handles thousands of concurrent operations — network requests, timers, user interactions — without blocking. The event loop is the mechanism that makes this possible, and understanding it is one of the most important (and most tested) JavaScript concepts.

The Call Stack

The call stack is a LIFO (Last-In, First-Out) data structure that tracks function execution. When a function is called, a new frame is pushed onto the stack containing its execution context (local variables, this binding, return address). When the function returns, its frame is popped off. JavaScript executes code by processing whatever is on top of the stack — only one function runs at a time.

If recursion goes too deep without a base case, the stack exceeds its size limit and throws RangeError: Maximum call stack size exceeded (stack overflow).

Web APIs / Node APIs

The runtime environment (browser or Node.js) provides APIs that operate outside the main thread. When you call setTimeout, fetch, or add an event listener, the browser hands the operation to its own internal threads. When the operation completes (timer expires, response arrives, event fires), the callback is placed into the appropriate queue — not directly onto the call stack.

Macrotask Queue (Task Queue)

Holds callbacks from: setTimeout, setInterval, I/O operations, UI rendering events, and setImmediate (Node.js). The event loop processes one macrotask per cycle.

Microtask Queue

Holds callbacks from: Promise.then/.catch/.finally, queueMicrotask(), MutationObserver, and the internal mechanics of async/await. Microtasks have higher priority than macrotasks.

The Event Loop Algorithm

The event loop follows this cycle continuously:

  1. Execute all synchronous code on the call stack until it's empty.
  2. Drain the entire microtask queue — run every microtask, including any new microtasks added during this step.
  3. Render updates if needed (browser repaint, layout).
  4. Pick one macrotask from the queue and execute it.
  5. Go back to step 2.

The critical insight: all microtasks run before the next macrotask. If a microtask enqueues another microtask, that also runs before any macrotask. This means Promise.resolve().then(callback) always executes before setTimeout(callback, 0), regardless of code order.

requestAnimationFrame

requestAnimationFrame(callback) runs after microtasks but before the browser paints — it's synchronized with the display refresh rate (typically 60fps). It's neither a macrotask nor a microtask. Use it for visual animations to ensure smooth rendering.

The Classic Interview Question

JavaScript
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');

Output: 1, 4, 3, 2. Synchronous code runs first (1, 4), then the microtask (3), then the macrotask (2).

Key Interview Distinction

JavaScript itself is single-threaded, but the runtime environment is not. The event loop bridges synchronous execution with asynchronous APIs. Microtasks always have priority over macrotasks — this explains why promise callbacks run before timer callbacks. Understanding this model is essential for predicting async execution order and avoiding performance pitfalls like microtask starvation (infinite microtask loops that block rendering).

Fun Fact

Philip Roberts' JSConf EU 2014 talk 'What the heck is the event loop anyway?' has over 8 million views on YouTube and is widely considered the definitive explanation of the event loop. His visualization tool Loupe lets you step through code and watch the call stack, Web APIs, and callback queue in real time.

Learn These First

Promises & Async/Await

intermediate

Continue Learning

Promises & Async/Await

intermediate

Memory Management & Garbage Collection

advanced

Practice What You Learned

Explain the JavaScript Event Loop and how it handles asynchronous operations.
mid
runtime
The Event Loop is JavaScript's mechanism for handling asynchronous operations. It continuously checks the call stack and task queues, executing callbacks from the microtask queue (Promises) before the macrotask queue (setTimeout, events).
What is the difference between microtasks and macrotasks in JavaScript?
mid
runtime
Microtasks (Promises, queueMicrotask, MutationObserver) run immediately after the current script and before any macrotasks. Macrotasks (setTimeout, setInterval, I/O) run one per event loop iteration. The microtask queue is fully drained before the next macrotask executes.
What is requestIdleCallback and how does it compare to other scheduling APIs?
senior
scheduling
requestIdleCallback schedules low-priority work to run during idle periods when the browser's main thread has no other tasks. Unlike requestAnimationFrame (which runs before every repaint) or setTimeout (which has a minimum delay), it runs only when the browser is truly idle.
How do WebSockets work and when would you use them over HTTP?
senior
runtime
WebSockets provide full-duplex, persistent communication between client and server over a single TCP connection. They start as an HTTP upgrade handshake, then switch to a lightweight binary-framed protocol. Use them for real-time features like chat, live notifications, collaborative editing, and live order tracking.
Previous
Prototypes & Inheritance
Next
Strings
PrevNext