Event Loop in JavaScript
JavaScript is synchronous single threaded language
It has one call Stack, it can be do one thing at a time. Call stack present in the JavaScript engine and all the code execute inside a call stack.
a endafter execution there are nothing more execute so they call Stack popped the global execution context and it will empty. so that is the whole JavaScript engine execute the JavaScript program.
- setTimeout()
- Dom APIs
- fetch()
- LocalStorage
- console
- Location
- ...
Supposed we want to used DOM / When run JS code execution context will created and pushed inside the call Stack.
- First line - it show console it goes inside browser and access console through web APIs and print start in console.
- Third line - document it is same like console, js goes to inside browser and access DOM () using window object . getElementById() it used for manipulating HTML and CSS. we can change or modify HTML and CSS using this.
- Forth line - addEventListener() is the another super power which given by the browser through the window in the form of web APIs which is the DOM Apis.
This WebAPIs enviroment a cb() will registered and that event with attached to it that is 'click' event. this is known as registering callback, then JavaScript engine go to the next line. and print end on console, all execution is done so Global execution context will popped to the callstack,
This work of event loop is to monitor the call Stack and callback Queue. if the call Stack is empty and event loop are sees that a function waiting to be executed inside the callback queue. so it take the function and pushed in the call stack and callback method quickly executed them.
start end callbackWhat is Micro-Queue, promises? how fetch() is work.
First setTimeout function are execute and it registered in webAPIs environment with attach a timer 5000ms and js engine goes to next line Fetch function are executed and it registered in webAPIs environment same like setTimeout.setTimeout(function cbT(){console.log('cb setTimeout');}, 5000);fetch("https://Simpleapi.com").then(function cbF(){console.log('cb api call')});console.log('End');
---------------------------------------------------------------------------------------------------------------------------------
Event Loop in JavaScript - The Complete Guide
Hey everyone! Welcome back to Namaste JavaScript. Today we are going to study one of the most important topics - Event Loop. After watching this, you will have a crystal clear understanding of Event Loop, Callback Queue, Microtask Queue, and how everything works inside the browser!
90% of JavaScript developers don't understand this topic properly. But after reading this blog, you will be in the top 10%!
What we will cover:
- What is Call Stack?
- Web APIs / Browser APIs
- Callback Queue (Task Queue)
- Microtask Queue
- How Event Loop works
- setTimeout example
- Promise and fetch example
- Priority: Microtask vs Callback Queue
First, Let's Understand the Call Stack
JavaScript is a single-threaded language. It has only ONE call stack and can execute one thing at a time.
Whenever you run JavaScript code, a Global Execution Context (GEC) is created and pushed into the call stack.
function a() {
console.log("a");
}
a();
console.log("End");
OUTPUT: a End
How it executes:
- GEC is pushed to call stack
- Function a() is called - its execution context is pushed
- "a" is printed
- a() finishes - its context is popped
- "End" is printed
- GEC is popped - call stack is empty
The Problem: JavaScript Needs Superpowers!
Call stack can only execute code. But what about:
- Timers (setTimeout, setInterval)
- Network calls (fetch, XMLHttpRequest)
- DOM manipulation
- Local Storage access
- Console logging
- Geolocation
These are NOT part of JavaScript! These are superpowers given by the Browser!
Web APIs - Browser's Superpowers
The browser is a remarkable creation. It has:
- JS Engine - where JavaScript code runs
- Web APIs - setTimeout, DOM APIs, fetch, localStorage, console, etc.
- Event Loop
- Callback Queue
- Microtask Queue
JavaScript accesses these superpowers through the window object!
// All these are Web APIs, not JavaScript! setTimeout() // window.setTimeout() localStorage // window.localStorage document // window.document fetch() // window.fetch() console.log() // window.console.log()
The window object is the global object that wraps all these superpowers and gives access to JavaScript!
Let's See How setTimeout Works
console.log("Start");
setTimeout(function cb() {
console.log("Callback");
}, 5000);
console.log("End");
OUTPUT: Start End Callback // After 5 seconds
Step by step execution:
- GEC is created and pushed to call stack
- "Start" is printed
- setTimeout is called - it registers the callback with Web API
- Timer starts in the browser (5000ms)
- JavaScript doesn't wait! Moves to next line
- "End" is printed
- GEC is popped - call stack is empty
- After 5 seconds, timer expires
- Callback function is pushed to Callback Queue
- Event Loop checks: Is call stack empty? YES!
- Event Loop pushes callback to call stack
- "Callback" is printed
What is the Callback Queue?
When async operations complete, their callbacks don't go directly to call stack. They go to Callback Queue and wait in line!
// Multiple callbacks waiting in queue setTimeout(cb1, 1000); setTimeout(cb2, 1000); setTimeout(cb3, 1000); // After 1 second, all three will be in Callback Queue // Callback Queue: [cb1, cb2, cb3] // Event Loop will pick them ONE BY ONE
What is Event Loop?
Event Loop has only ONE job:
Continuously monitor the Call Stack and Callback Queue. When call stack is empty, pick the first callback from queue and push it to call stack.
// Event Loop's job (simplified):
while(true) {
if (callStack.isEmpty() && callbackQueue.hasCallbacks()) {
callStack.push(callbackQueue.shift());
}
}
Event Listeners and Callback Queue
console.log("Start");
document.getElementById("btn").addEventListener("click", function cb() {
console.log("Button Clicked!");
});
console.log("End");
OUTPUT: Start End // When button is clicked: Button Clicked!
How it works:
- "Start" is printed
- Event listener is registered with Web API
- Callback is attached to "click" event
- "End" is printed
- GEC is popped
- When user clicks button - callback goes to Callback Queue
- Event Loop pushes it to call stack
- "Button Clicked!" is printed
Important: If you click the button 5 times, 5 callbacks will be queued!
Now Comes the Interesting Part - Microtask Queue!
There's another queue called Microtask Queue. It has HIGHER PRIORITY than Callback Queue!
What goes into Microtask Queue?
- Promise callbacks (.then, .catch, .finally)
- Mutation Observer callbacks
What goes into Callback Queue (Task Queue)?
- setTimeout callbacks
- setInterval callbacks
- Event listener callbacks (click, scroll, etc.)
Microtask Queue vs Callback Queue - Example
console.log("Start");
setTimeout(function cbT() {
console.log("CB setTimeout");
}, 0);
fetch("https://api.example.com/data")
.then(function cbF() {
console.log("CB fetch");
});
console.log("End");
OUTPUT: Start End CB fetch // Microtask Queue - Higher Priority! CB setTimeout // Callback Queue - Lower Priority
Why this order?
- "Start" is printed
- setTimeout callback goes to Callback Queue (after 0ms)
- fetch is called - network request starts
- "End" is printed
- GEC is popped
- Assume fetch returns super fast
- fetch callback goes to Microtask Queue
- Event Loop checks: Microtask Queue has higher priority!
- "CB fetch" is printed first
- Then "CB setTimeout" is printed
Event Loop Priority
// Event Loop checks in this order: 1. Is Call Stack empty? 2. Any callbacks in Microtask Queue? → Execute ALL of them first! 3. Any callbacks in Callback Queue? → Execute one 4. Repeat
Important: Event Loop will empty the ENTIRE Microtask Queue before touching Callback Queue!
Complete Example - Putting It All Together
console.log("Start");
setTimeout(function cb1() {
console.log("CB1 - setTimeout");
}, 0);
Promise.resolve().then(function cb2() {
console.log("CB2 - Promise");
});
Promise.resolve().then(function cb3() {
console.log("CB3 - Promise");
});
setTimeout(function cb4() {
console.log("CB4 - setTimeout");
}, 0);
console.log("End");
OUTPUT: Start End CB2 - Promise // Microtask Queue CB3 - Promise // Microtask Queue CB1 - setTimeout // Callback Queue CB4 - setTimeout // Callback Queue
Execution flow:
- "Start" printed (synchronous)
- cb1 registered → Callback Queue
- cb2 registered → Microtask Queue
- cb3 registered → Microtask Queue
- cb4 registered → Callback Queue
- "End" printed (synchronous)
- Call stack empty!
- Event Loop: Check Microtask Queue first!
- cb2 executed → "CB2 - Promise"
- cb3 executed → "CB3 - Promise"
- Microtask Queue empty, check Callback Queue
- cb1 executed → "CB1 - setTimeout"
- cb4 executed → "CB4 - setTimeout"
Starvation of Callback Queue
What if Microtask Queue keeps getting new tasks?
// DANGEROUS - DON'T DO THIS!
function addMicrotask() {
Promise.resolve().then(() => {
console.log("Microtask");
addMicrotask(); // Creates another microtask!
});
}
addMicrotask();
setTimeout(() => {
console.log("I will NEVER run!");
}, 0);
OUTPUT: Microtask Microtask Microtask ... (infinite loop!) // setTimeout callback NEVER gets a chance!
This is called Starvation - Callback Queue never gets a chance because Microtask Queue is never empty!
Quick Recap - Interview Cheat Sheet
| Component | Purpose |
|---|---|
| Call Stack | Executes JavaScript code one at a time |
| Web APIs | Browser superpowers (setTimeout, fetch, DOM, etc.) |
| Callback Queue | Holds setTimeout, setInterval, event callbacks |
| Microtask Queue | Holds Promise callbacks, MutationObserver (Higher Priority!) |
| Event Loop | Moves callbacks from queues to call stack when empty |
Interview Tips - How to Explain
Q: What is Event Loop?
"Event Loop is a mechanism that continuously monitors the Call Stack and Callback Queues. When the call stack is empty, it picks callbacks from the queues and pushes them to the call stack for execution. It gives priority to Microtask Queue over Callback Queue."
Q: What is the difference between Microtask Queue and Callback Queue?
"Microtask Queue holds Promise callbacks and MutationObserver callbacks. Callback Queue holds setTimeout, setInterval, and event listener callbacks. Microtask Queue has higher priority - Event Loop will empty the entire Microtask Queue before picking anything from Callback Queue."
Q: Why does setTimeout with 0ms still execute after synchronous code?
"Even with 0ms delay, the callback goes through Web API → Callback Queue → Event Loop. The Event Loop only pushes it to Call Stack when the stack is empty, which happens after all synchronous code finishes."
Key Points to Remember
- JavaScript has only ONE call stack (single-threaded)
- Web APIs are browser superpowers, not JavaScript
- Access Web APIs through window object
- Callback Queue: setTimeout, setInterval, events
- Microtask Queue: Promises, MutationObserver
- Microtask Queue has HIGHER priority!
- Event Loop's job: Move callbacks to call stack when empty
- Event Loop empties entire Microtask Queue first
- Starvation: When Callback Queue never gets a chance
Keep coding, keep learning!
Post a Comment