DEV Community

Mahmudul Fahim
Mahmudul Fahim

Posted on

πŸ”„ JavaScript Event Loop: The Thing You Use Daily But Never See!

We write JavaScript every day. We use async/await, setTimeout, make API calls. But have you ever wondered β€” how does all of this actually work?

Today I'm going to break down one of the most important yet least understood topics in JavaScript β€” The Event Loop.

πŸ€” What Exactly Is the Event Loop?
JavaScript is a single-threaded language. That means it can only do one thing at a time. But we do many things simultaneously β€” API calls, timers, user click events β€” all at once!

How is this possible?

πŸ‘‰ The answer is the Event Loop!

The Event Loop is the mechanism that makes JavaScript behave non-blocking and asynchronous.

🧠 The Main Parts of JavaScript Runtime:
text
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Call Stack β”‚
β”‚ (What's running now) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Web APIs / Node APIs β”‚
β”‚ (Browser/Backend features)β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Callback Queue β”‚
β”‚ (Tasks waiting in line) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Event Loop β”‚
β”‚ (The traffic controller) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
🎯 Let's Understand Each Part:
1️⃣ Call Stack (The Doer)
This is where your code actually runs

It's a LIFO (Last In, First Out) structure

Functions are pushed onto the stack when called, and popped off when they return

Example:

javascript

function add(a, b) {
  return a + b;
}

function multiply(a, b) {
  return a * b;
}

function calculate() {
  const sum = add(5, 10);
  const result = multiply(sum, 2);
  console.log(result);
}

calculate();
Enter fullscreen mode Exit fullscreen mode

How the stack works:

calculate() β†’ pushed to stack

add(5, 10) β†’ pushed to stack (runs, returns, popped)

multiply(15, 2) β†’ pushed to stack (runs, returns, popped)

console.log(30) β†’ pushed to stack (runs, popped)

calculate() β†’ popped from stack

Stack is now empty! βœ…

2️⃣ Web APIs / Node.js APIs (The Helpers)
These are provided by the browser or Node.js (not JavaScript itself)

Examples: setTimeout, fetch, DOM events, fs.readFile

They handle async operations in the background while the stack runs other code

Example:

javascript

console.log('Start');

setTimeout(() => {
  console.log('Inside setTimeout');
}, 2000);

console.log('End');
Enter fullscreen mode Exit fullscreen mode

What happens step by step:

console.log('Start') β†’ runs immediately

setTimeout β†’ handed off to Web API (timer starts)

console.log('End') β†’ runs immediately (doesn't wait!)

After 2 seconds, the callback moves to the queue

Event Loop checks if the stack is empty β†’ then puts it on the stack

Output:

text
Start
End
Inside setTimeout
Enter fullscreen mode Exit fullscreen mode

3️⃣ Callback Queue (The Waiting Area)
Also called Task Queue or Macro Task Queue

Holds callbacks waiting to be executed

Follows FIFO (First In, First Out) order

Types of Queues:

Macro Task Queue: setTimeout, setInterval, I/O, UI rendering

Micro Task Queue: Promise.then, MutationObserver, queueMicrotask

Micro Task Queue has higher priority! ⚑

4️⃣ Event Loop (The Traffic Controller)
The Event Loop is a continuous running process

It constantly checks: Is the Call Stack empty?

If empty, it takes tasks from the queue and pushes them to the stack

The Priority Order:

First, execute all Micro Tasks (Promises)

Then execute one Macro Task (setTimeout)

Repeat!

Visualization:

text
Event Loop continuously checks:
Is Call Stack empty? β†’ YES β†’ Take from Queue β†’ Push to Stack
β†’ NO β†’ Wait
πŸ”₯ Let's See It All Together:
What do you think the output will be? πŸ€”

javascript

console.log('1️⃣ Start');

setTimeout(() => {
  console.log('2️⃣ setTimeout');
}, 0);

Promise.resolve().then(() => {
  console.log('3️⃣ Promise');
});

console.log('4️⃣ End');
Enter fullscreen mode Exit fullscreen mode

Output:

text
1️⃣ Start
4️⃣ End
3️⃣ Promise
2️⃣ setTimeout
Why this order?

Start and End β†’ immediately on the stack

setTimeout β†’ sent to Web API, then Macro Task Queue

Promise β†’ sent to Micro Task Queue (higher priority!)

Event Loop processes all Micro Tasks first β†’ Promise runs

Then processes Macro Tasks β†’ setTimeout runs

Surprised? Most developers are! πŸ˜…

πŸ’‘ Why This Matters:
βœ… Avoid Blocking the Main Thread
javascript

// ❌ BAD - This will block everything for 5 seconds!
function heavyTask() {
  const start = Date.now();
  while (Date.now() - start < 5000) {
    // Nothing - just wasting time!
  }
  console.log('Done');
}

// βœ… GOOD - Use async operations
function heavyTask() {
  setTimeout(() => {
    console.log('Done');
  }, 5000);
}
Enter fullscreen mode Exit fullscreen mode

βœ… Understand Async Code
javascript

// The classic interview question:
for (var i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i);
  }, 1000);
}

// Output: 3, 3, 3 ❌ (Not 0, 1, 2!)
// Why? By the time setTimeout runs, i is already 3!
Enter fullscreen mode Exit fullscreen mode

Fix using let instead of var (creates block scope):

javascript

for (let i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i); // 0, 1, 2 βœ…
  }, 1000);
}
Enter fullscreen mode Exit fullscreen mode

βœ… Write Better Code
Make API calls properly with async/await

Handle promises correctly

Use setTimeout(0) to defer execution

πŸ“ Key Takeaways:
Concept What It Does
Call Stack Executes functions (synchronous)
Web APIs Handles async tasks in background
Task Queue Holds callbacks waiting to run
Micro Task Queue Holds promises (Higher priority!)
Event Loop Moves tasks from queue to stack when empty
🎯 Summary:
JavaScript is single-threaded but non-blocking

The Event Loop is the mechanism that makes async possible

Micro Tasks (Promises) run before Macro Tasks (setTimeout)

Understanding the Event Loop helps you write better, faster, non-blocking code

Always think about "What's on the stack?" when debugging async issues

πŸ’¬ Let's Discuss:
Question for you: Have you ever faced a situation where your async code didn't behave as expected? How did you debug it?

Drop your experience in the comments! πŸ‘‡

Top comments (0)