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.

Any JavaScript code is run, execution context is created and pushed inside the Call Stack. then this code execute line by line. JavaScript engine go to line 4. this is a function invocation a() so again create a execution context and push inside the call stack. This a() run line by line and print a over here.

then this a() execution is done. it's deleted or popped. the control move one line 5 that is console.log('end'); so it print end our output show line.

a
end
after 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.

Web APIs in JavaScript
This is the power of JavaScript
  • setTimeout()
  • Dom APIs
  • fetch()
  • LocalStorage
  • console
  • Location
  • ...
This is the WebAPIs. it's not part of JavaScript. yeah infact console is not part of JavaScript. this is the features of Browser. in short this is a external super power of JavaScript.
We can used this WebAPIs in JS using window object. bcz window is a global object so it help to connect this features inside a JavaScript engine using web APIs.
JavaScript engine gives the facility to used all this super power with the help of window

How it work?

Supposed we want to use console method to our code, we can easily access this using window.console.log() and it work.

but ? we do not use window.console.log() we just a put consolo.log() and it work. how?
because window is a global keyword and all this powers / features inside it in window object. that's why, if we write a window.console or console it that same thing, 

How Web APIs work internally?

Supposed we want to used DOM  / When run JS code execution context will created and pushed inside the call Stack.
  1. First line - it show console it goes inside browser and access console through web APIs and print start in console.
  2.  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.
  3. 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.
DOM means the document object model it is represent the html page. we can change the document structure, style and content using DOM ApIs. DOM APIs it access this HTML code and try to find button with id 'btn' and return it.  and .addEventListener() register a callback on an event, that event is click. .addEventListener('click', function cb(){});  
T
    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, 

    But the cb() is wait in web API env. if user click the button then the cb() pushed inside the callback queue. 

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.
When the callback execution is complete, the cb() will popup inside the callStack .
start
end
callback
What is Micro-Queue, promises? how fetch() is work.
Fetch is used to request API's call. This fetch() function return a promise. we have to pass a callback function which will be executed once is promise is resolved. 
  
setTimeout(function cbT(){
    console.log('cb setTimeout');
}, 5000);

fetch("https://Simpleapi.com").then(function cbF(){
    console.log('cb api call')
});

console.log('End');
    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.
    When the timer are expired this cbt() goes to callback queue. and cbf() function is waiting for return data form the server. when server return the data back to fetch once we get the data and cbf() function is ready to execute it goes to micro-task queue.  


    Micro-task queue and callback queue are same means it's work same but Microtask queue has higher priority. whatever callback function are come in microtask queue that is called as mutation observer
 it will be execute first then execute callback queue.
    The callback function in case of promises it goes to the microtask queue. and the Event loop job is to see the callstack is empty or not. if callstack is empty the callback function push inside the callstack and execute. if microtask all execution will complited. then callback queue inside function is start to execute. 
    




---------------------------------------------------------------------------------------------------------------------------------

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:

  1. GEC is pushed to call stack
  2. Function a() is called - its execution context is pushed
  3. "a" is printed
  4. a() finishes - its context is popped
  5. "End" is printed
  6. 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:

  1. GEC is created and pushed to call stack
  2. "Start" is printed
  3. setTimeout is called - it registers the callback with Web API
  4. Timer starts in the browser (5000ms)
  5. JavaScript doesn't wait! Moves to next line
  6. "End" is printed
  7. GEC is popped - call stack is empty
  8. After 5 seconds, timer expires
  9. Callback function is pushed to Callback Queue
  10. Event Loop checks: Is call stack empty? YES!
  11. Event Loop pushes callback to call stack
  12. "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:

  1. "Start" is printed
  2. Event listener is registered with Web API
  3. Callback is attached to "click" event
  4. "End" is printed
  5. GEC is popped
  6. When user clicks button - callback goes to Callback Queue
  7. Event Loop pushes it to call stack
  8. "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?

  1. "Start" is printed
  2. setTimeout callback goes to Callback Queue (after 0ms)
  3. fetch is called - network request starts
  4. "End" is printed
  5. GEC is popped
  6. Assume fetch returns super fast
  7. fetch callback goes to Microtask Queue
  8. Event Loop checks: Microtask Queue has higher priority!
  9. "CB fetch" is printed first
  10. 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:

  1. "Start" printed (synchronous)
  2. cb1 registered → Callback Queue
  3. cb2 registered → Microtask Queue
  4. cb3 registered → Microtask Queue
  5. cb4 registered → Callback Queue
  6. "End" printed (synchronous)
  7. Call stack empty!
  8. Event Loop: Check Microtask Queue first!
  9. cb2 executed → "CB2 - Promise"
  10. cb3 executed → "CB3 - Promise"
  11. Microtask Queue empty, check Callback Queue
  12. cb1 executed → "CB1 - setTimeout"
  13. 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!