Why Event Loop?
JavaScript is a single-threaded language, which means it executes one task at a time. But how does JavaScript handle asynchronous operations like setTimeout(), fetch(),Promises and ? The answer lies in the Event Loop, which ensures smooth execution of tasks by managing different queues. The diagram Below illustrates how the Call Stack, Web APIs, Microtask Queue, and Macrotask Queue interact within the JavaScript engine.

Event Loop
The event loop, as illustrated in the diagram, is a key mechanism in the JavaScript engine that manages the execution of asynchronous tasks. It continuously checks the call stackand the task queues (Microtask Queue and Macrotask Queue)to ensure smooth, non-blocking execution.
The Call Stack: Where Execution Happens
The Call Stack is where JavaScript executes functions. It follows a Last In, First Out (LIFO) principle, meaning the last function added is the first one executed.
console.log("Hi");
console.log("Hello");
These statements are executed synchronously, meaning they are processed immediately before moving to asynchronous tasks.
Web APIs: Handling Asynchronous Operations
When we call asynchronous functions like setTimeout(), fetch(), or setInterval(), JavaScript Engine offloads them to the Web APIs provided by the browser.
Microtask Queue (High Priority Tasks)
Microtasks consist of operations that must be executed before any macrotasks. These include:
- Promises (then(), catch(), finally())
- MutationObserver
- queueMicrotask API
When a Promise settles (either resolves or rejects), its callback is added to the Microtask Queue. The Event Loop processes all microtasks before moving to macrotasks.
Macrotask Queue (Low Priority Tasks)
Macrotasks (also known as the Callback Queue) include:
- setTimeout(), setInterval()
- I/O Operations
- etc.
Once the Call Stack is empty, JavaScript moves to the Microtask Queue first. Only after all microtasks are completed, the Event Loop picks tasks from the Macrotask Queue.
The Event Loop: The Heart of JavaScript
The Event Loop continuously checks:
- ✔ If the Call Stack is empty
- ✔ If there are Microtasks to execute
- ✔ If all Microtasks are done, then it moves to Macrotasks
Web APIs, setTimeout(), and the Event Loop
setTimeout() is immediately registered in the Web APIs when it is encountered in the code, but its callback function is queued for execution only after the specified delay.
- Encountering setTimeout()
- When JavaScript sees a
setTimeout()function, it registers the timer immediately in the Web APIs with the specified delay.
- When JavaScript sees a
- Timer Starts Running
- The Web API starts counting down the specified time (e.g.,
1000msforsetTimeout(() => console.log("Timer finished"), 1000);).
- The Web API starts counting down the specified time (e.g.,
- Time Expired → Move to the Macrotask Queue
- After
1000ms, the callback function (console.log("Timer finished")) is moved to the Macrotask Queue (also called the Callback Queue).
- After
- Event Loop Picks the Task
- The Event Loop constantly checks the Call Stack:
- If the Call Stack is empty and all Microtasks (like Promises) are done, then it moves the
setTimeout()callback from the Macrotask Queue to the Call Stack for execution.
Questions practice for better understanding
Let's do some question on event loop for better undertanding
Question 1console.log("A");
setTimeout(() => console.log("B"), 0);
Promise.resolve().then(() => console.log("C"));
console.log("D"); - Step 1: "A" is logged synchronously.
- Step 2:
setTimeoutis scheduled in the Macrotask Queue. - Step 3: The Promise is resolved, and its
.then()callback is added to the Microtask Queue. - Step 4: "D" is logged synchronously.
- Step 5: The Microtask Queue executes, logging "C".
- Step 6: Finally, the Macrotask from
setTimeoutexecutes, logging "B".
console.log(1);
setTimeout(() => console.log(2), 100);
setTimeout(() => console.log(3), 0);
Promise.resolve().then(() => console.log(4));
console.log(5); - Step 1: 1 is logged synchronously.
- Step 2:
setTimeout(() => console.log(2), 100)is scheduled to the Macrotask Queue with a 100ms delay. - Step 3:
setTimeout(() => console.log(3), 0)is scheduled to the Macrotask Queue (0ms delay). - Step 4: The Promise's
.then(() => console.log(4))callback is added to the Microtask Queue. - Step 5: 5 is logged synchronously.
- Step 6: The Microtask Queue executes first, logging 4.
- Step 7: Then, the Macrotasks run: first the 0ms timeout logs 3, and after 100ms, 2 logs.
setTimeout(() => console.log("X"), 0);
Promise.resolve().then(() => {
console.log("Y");
return Promise.resolve(); }).then(() => console.log("Z"));
console.log("W"); - Step 1:
setTimeout(() => console.log("X"), 0)schedules "X" in the Macrotask Queue. - Step 2: The Promise's first
.then()is queued in the Microtask Queue. - Step 3: "W" is logged synchronously.
- Step 4: Microtasks run next: "Y" is logged, then the subsequent
.then()logs "Z". - Step 5: Finally, the Macrotask executes, logging "X".
console.log(10);
setTimeout(() => console.log(20), 0);
Promise.resolve().then(() => { console.log(30); setTimeout(() => console.log(40), 0); });
console.log(50); - Step 1: 10 is logged synchronously.
- Step 2:
setTimeout(() => console.log(20), 0)is scheduled to the Macrotask Queue. - Step 3: The Promise's
.then(() => console.log(30))callback is added to the Microtask Queue. - Step 4: 50 is logged synchronously.
- Step 5: Microtasks run, logging 30; within that callback, a new
setTimeout(() => console.log(40), 0)is scheduled. - Step 6: The Macrotasks then execute: first, the 0ms timeout logs 20, then the newly scheduled one logs 40.
setTimeout(() => console.log("P"), 0);
Promise.resolve().then(() => console.log("Q")) .then(() => console.log("R"));
setTimeout(() => console.log("S"), 0);
console.log("T"); - Step 1:The first
setTimeout(() => console.log("P"), 0);schedules"P"in theMacrotask Queue. - Step 2:
Promise.resolve()immediately resolves, and its first.then(() => console.log("Q"))is added to the Microtask Queue. - Step 3:The second
.then(() => console.log("R"))is also added to the Microtask Queue, but it will execute only after"Q"completes. - Step 4:The second
setTimeout(() => console.log("S"), 0);schedules"S"in theMacrotask Queue as well, after"P". - Step 5:The synchronous
console.log("T")executes immediately and logs"T". - Step 6:The Microtask Queue executes next:
"Q"is logged first, then"R". - Step 7:After all microtasks are completed, theMacrotask Queue runs:
"P"(from the firstsetTimeout) is logged."S"(from the secondsetTimeout) is logged.
Key Rule:
In each cycle of the Event Loop, Microtasks always execute before Macrotasks in the browser. This means that after the **Call Stack** is cleared, the browser first processes all pending Microtasks (such as Promise.then()) before moving on to any Macrotasks (such as setTimeout,setInterval).