One of the most frequently asked JavaScript interview questions is:

How does the JavaScript Event Loop work?

This question appears in:

  • Frontend Interviews
  • React Interviews
  • Senior JavaScript Interviews
  • Full Stack Interviews

Interviewers often ask:

  • Is JavaScript single-threaded?
  • How can JavaScript perform asynchronous operations?
  • What is the Event Loop?
  • What are Microtasks and Macrotasks?
  • Why do Promises execute before setTimeout?

To answer these questions, we need to understand how JavaScript executes code behind the scenes.

1. Is JavaScript Single-Threaded?#

Yes.

JavaScript executes code on a single thread.

This means:

One Task At A Time

Example:

JAVASCRIPT
console.log("A");

console.log("B");

console.log("C");

Output:

A
B
C

JavaScript cannot execute:

A and B simultaneously

on the same thread.

2. The Problem of Blocking Operations#

Consider:

JAVASCRIPT
console.log("Start");

setTimeout(() => {
  console.log("Timer");
}, 5000);

console.log("End");

Output:

Start
End
Timer

Question:

If JavaScript is single-threaded, why doesn't it wait 5 seconds?

The answer lies in:

Event Loop

3. What is the Event Loop?#

The Event Loop is a mechanism that allows JavaScript to perform asynchronous operations without blocking the main thread.

It coordinates:

  • Call Stack
  • Web APIs
  • Callback Queue
  • Microtask Queue

Together they enable asynchronous behavior.

4. Key Components: Call Stack & Web APIs#

The Event Loop relies on four major components:

Call Stack
Web APIs
Callback Queue
Event Loop

Modern JavaScript also includes:

Microtask Queue

Call Stack#

The Call Stack keeps track of currently executing functions.

Example:

JAVASCRIPT
function greet() {
  console.log("Hello");
}

greet();

Execution:

Call Stack

greet()
 ↓
console.log()

After execution:

Call Stack Empty

Stack Example#

JAVASCRIPT
function one() {
  two();
}

function two() {
  three();
}

function three() {
  console.log("Done");
}

one();

Call Stack:

one()
 ↓
two()
 ↓
three()
 ↓
console.log()

Then functions are removed one by one.

Web APIs#

Browsers provide APIs outside JavaScript itself.

Examples:

JAVASCRIPT
setTimeout
fetch
DOM Events
addEventListener
Geolocation

These APIs are handled by the browser.

Not by the JavaScript engine.

Example#

JAVASCRIPT
setTimeout(() => {
  console.log("Timer");
}, 3000);

Execution:

Call Stack
    ↓
Browser Web API
    ↓
Wait 3 Seconds
    ↓
Queue Callback

The timer does not sit on the Call Stack.

5. Callback Queue (Macrotasks)#

After an asynchronous task completes:

JAVASCRIPT
setTimeout(...)

its callback is placed into the:

Callback Queue

Example:

JAVASCRIPT
setTimeout(() => {
  console.log("Timer");
}, 0);

After timer completion:

Callback Queue

console.log("Timer")

The callback waits until the Call Stack becomes empty.

Event Loop's Job#

The Event Loop continuously checks:

Is Call Stack Empty?

If yes:

Move Task From Queue
To Call Stack

This process repeats forever.

Visual Representation#

Call Stack
     ↑
     |
Event Loop
     |
     ↓
Callback Queue

First Interview Question#

What is the output?

JAVASCRIPT
console.log("Start");

setTimeout(() => {
  console.log("Timer");
}, 0);

console.log("End");

Answer#

Output:

Start
End
Timer

Why?

Even:

JAVASCRIPT
setTimeout(..., 0)

does not execute immediately.

The callback must first enter the queue and wait for the Call Stack to become empty.

6. Promises & the Microtask Queue#

Promises do not use the Callback Queue.

They use:

Microtask Queue

Example:

JAVASCRIPT
Promise.resolve().then(() => {
  console.log("Promise");
});

Two Important Queues#

Microtask Queue
Macrotask Queue

Examples:

Microtasks

JAVASCRIPT
Promise.then()
catch()
finally()
queueMicrotask()
MutationObserver

Macrotasks

JAVASCRIPT
setTimeout()
setInterval()
DOM Events
MessageChannel

7. Queue Priority: Microtasks vs. Macrotasks#

The Event Loop always processes:

Microtasks First

before:

Macrotasks

This is one of the most important interview concepts.

Promise vs setTimeout#

What is the output?

JAVASCRIPT
console.log("Start");

setTimeout(() => {
  console.log("Timer");
}, 0);

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

console.log("End");

Answer#

Output:

Start
End
Promise
Timer

Why?

Execution:

Start
End

Then:

Microtask Queue
 ↓
Promise

Then:

Macrotask Queue
 ↓
Timer

Microtasks always run first.

8. Async/Await and the Event Loop#

Consider:

JAVASCRIPT
async function demo() {
  console.log("A");

  await Promise.resolve();

  console.log("B");
}

demo();

console.log("C");

Answer#

Output:

A
C
B

Why?

await creates a Promise continuation.

The remaining code:

JAVASCRIPT
console.log("B");

is placed into the:

Microtask Queue

9. Event Loop Execution Order#

The Event Loop follows:

1. Execute Sync Code
2. Empty Microtask Queue
3. Execute One Macrotask
4. Empty Microtask Queue Again
5. Repeat

This order is extremely important.

Advanced Interview Question#

What is the output?

JAVASCRIPT
console.log("1");

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

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

console.log("4");

Answer#

Output:

1
4
3
2

Explanation:

1 → Sync
4 → Sync
3 → Microtask
2 → Macrotask

Advanced Interview Question#

What is the output?

JAVASCRIPT
console.log("1");

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

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

    return Promise.resolve();
  })
  .then(() => {
    console.log("4");
  });

console.log("5");

Answer#

Output:

1
5
3
4
2

Why?

All microtasks finish before any macrotask begins.

10. Browser Rendering and the Event Loop#

Browsers typically render:

After Current Task Completes

Example:

JAVASCRIPT
button.style.color = "red";

while (true) {}

The UI may never update because the thread is blocked.

Why Long Tasks Are Bad#

Example:

JAVASCRIPT
while (true) {
  // Infinite loop
}

Result:

Blocked Event Loop

Effects:

  • Frozen UI
  • Delayed timers
  • Unresponsive application

11. Common Interview Q&A#

Does setTimeout(0) Execute Immediately?#

No.

It enters the Macrotask Queue and waits.

Why Do Promises Execute Before Timers?#

Because Promise callbacks are Microtasks.

Microtasks have higher priority.

Is JavaScript Multithreaded?#

The JavaScript execution thread is single-threaded.

However, browsers provide asynchronous capabilities through Web APIs.

Does Await Block JavaScript?#

No.

It pauses only the current async function.

The Event Loop continues running.

What Queue Does Promise.then() Use?#

Microtask Queue

What Queue Does setTimeout() Use?#

Macrotask Queue

Senior-Level Interview Answer#

JavaScript is single-threaded and executes code using a Call Stack. Asynchronous operations such as timers, network requests, and DOM events are handled by browser Web APIs. Once completed, their callbacks are placed into task queues. The Event Loop continuously checks whether the Call Stack is empty and then moves queued tasks onto the stack for execution. Promise callbacks and async/await continuations are scheduled as Microtasks, while setTimeout callbacks are scheduled as Macrotasks. The Event Loop always processes all Microtasks before executing the next Macrotask, which is why Promise callbacks execute before timers.

Common Interview Mistakes#

❌ "JavaScript is asynchronous."

Correct:

JavaScript is synchronous and single-threaded.
The Event Loop enables asynchronous behavior.

❌ "setTimeout(0) executes immediately."

Correct:

It waits for the Call Stack to become empty.

❌ "Promises use the Callback Queue."

Correct:

Promises use the Microtask Queue.

❌ "Await blocks JavaScript."

Correct:

Await pauses only the current async function.

Event Loop Summary#

ComponentResponsibility
Call StackExecutes functions
Web APIsHandle async operations
Microtask QueuePromise callbacks
Macrotask QueueTimers and events
Event LoopCoordinates execution

Key Takeaways#

  • Single-Threaded JS: The JS runtime handles one task at a time using a Call Stack, offloading async tasks to Web APIs.
  • Microtask Priority: The Microtask Queue (Promises) is completely flushed before the next Macrotask Queue item (timers) executes.
  • Event Loop: Monitors the Call Stack and moves callbacks from queues onto the stack once it is empty.
  • Browser Rendering: Updates generally occur between event ticks once the stack clears, blocked by long-running loops.