🔄

JavaScript Event Loop

Call stack, task queue, microtasks, and async execution

The JavaScript Event Loop

Understanding async execution in a single-threaded environment

JavaScript is single-threaded, meaning it can only execute one piece of code at a time. Yet it handles async operations like network requests, timers, and user interactions smoothly. The secret? The Event Loop.

Understanding the event loop is crucial for writing performant JavaScript and predicting the order of async operations. It's also a favorite topic in technical interviews when discussing concepts like Promises, setTimeout, and why certain code executes in unexpected orders.

How the Event Loop Works

The continuous cycle of checking and executing

Event Loop Cycle

Watch how JavaScript coordinates between the call stack, microtasks, and macrotasks

Web APIs (Browser)

setTimeout()
fetch()
DOM Events

JavaScript Engine

Call Stack
Heap
Objects
Event Loop

Callback Queues

Microtask Queue (Priority)
Promise
Promises, queueMicrotask
Task Queue (Macrotasks)
setTimeout
click
setTimeout, setInterval, I/O
Render Steps
Style, Layout, Paint
Step 1: Check Call Stack

Event loop first checks if the call stack has any frames to execute

1

Microtasks First

All microtasks run before the next macrotask. Promises always resolve before setTimeout, even with 0ms delay.

2

One Task at a Time

Only one macrotask is processed per loop iteration. This allows rendering updates between tasks.

The Call Stack

Tracking function execution in LIFO order

Call Stack Visualization

See how functions are pushed and popped from the stack

Code Execution
1 function third() {
2 console.log("third");
3 }
4
5 function second() {
6 third();
7 }
8
9 function first() {
10 second();
11 }
12
13 function main() {
14 first();
15 }
16
17 main();

Call Stack (LIFO)

main() (top)
Bottom of stack Top of stack (executes first)
Push
Function called = added to top
Pop
Function returns = removed
Script Starts

main() is pushed onto the call stack

!

Stack Overflow

If functions keep calling other functions without returning, the stack grows until it exceeds the browser's limit (~10,000-50,000 frames), causing a Maximum call stack size exceeded error. This commonly happens with infinite recursion.

Microtasks vs Macrotasks

Understanding queue priorities

Queue Priority

Microtasks always run before the next macrotask

Example Code
// Synchronous
console.log('start');

// Macrotask (Task Queue)
setTimeout(() => {
  console.log('timeout');
}, 0);

// Microtask (higher priority)
Promise.resolve().then(() => {
  console.log('promise');
});

// Synchronous
console.log('end');
Console Output
Waiting...

Execution Priority

Sync
Microtasks
Macrotasks

Microtask Queue

HIGH PRIORITY
Promise.then
Promise.then(), queueMicrotask(), MutationObserver

Task Queue (Macrotasks)

LOW PRIORITY
setTimeout
setTimeout(), setInterval(), I/O, UI events
Step 1: Initial State

Code schedules async tasks: setTimeout and Promise.resolve()

!

The Golden Rule

Microtasks always run before macrotasks. Even if setTimeout has 0ms delay, Promise.then() callbacks execute first because they're in the microtask queue. This is why the output is: start, end, promise, timeout.

Execution Order Examples

Predict the output of async code

Common Interview Questions

Test your understanding of event loop execution order

Basic Promise vs setTimeout

Code What's the output?
console.log('1');

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

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

console.log('4');

Quick Reference: What Goes Where?

Microtask Queue
  • Promise.then() / .catch() / .finally()
  • queueMicrotask()
  • MutationObserver callbacks
  • await (code after await)
Task Queue (Macrotasks)
  • setTimeout() / setInterval()
  • setImmediate() (Node.js)
  • I/O operations
  • UI rendering events
  • requestAnimationFrame (before paint)
1

Execution Order

Sync code always runs first. Then all microtasks. Then one macrotask. Repeat.

2

Microtask Starvation

If microtasks keep adding more microtasks, macrotasks (and rendering) get blocked indefinitely.

3

setTimeout(fn, 0)

Doesn't run immediately! It schedules a macrotask that runs after sync code and all microtasks.

Key Terms to Remember

Master these terms for technical interviews