DEV Community

Cover image for 🚦 Understanding the JavaScript Event Loop: A Story You’ll Remember
Applexity.Ox
Applexity.Ox

Posted on

🚦 Understanding the JavaScript Event Loop: A Story You’ll Remember

The first time I saw this little piece of code, I was confused:

console.log("Start");

setTimeout(() => console.log("Timeout"), 0);

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

And the output was:

Start  
End  
Timeout
Enter fullscreen mode Exit fullscreen mode

Wait… why “Timeout” after “End”? Didn’t I set the delay to 0? For me, that was the moment I realized JavaScript has its own rhythm. It doesn’t just run line by line - there’s an invisible system deciding when things happen. That system is called the event loop.

🛑 The Call Stack : Our One-Lane Road

Imagine you’re standing at a traffic signal on a narrow one-lane road. Only one car can pass at a time. Each car waits for the one in front to move before it can go. That’s exactly how JavaScript works with its call stack.

When you call a function in JavaScript, it’s like a car entering that road. The engine pushes the function onto the call stack. When the function is done, the car exits, making way for the next one.

So if I write:

function greet() {
  console.log("Hello");
}
greet();
console.log("Done");
Enter fullscreen mode Exit fullscreen mode

It’s just cars moving in order: greet() enters, prints “Hello”, exits, then “Done” runs. Nothing surprising here. But what if one car is a giant truck that takes forever to pass?

🚛 The Blocking Truck

Let’s say one day, instead of a small car, a giant truck pulls up to the one-lane road. It takes forever to move. Now, all the other cars behind it are stuck waiting. That’s what happens when we run heavy code in JavaScript.

function bigTask() {
  for (let i = 0; i < 1e9; i++) {} // long loop
  console.log("Big task done");
}
bigTask();
console.log("Next task");
Enter fullscreen mode Exit fullscreen mode

Here, the loop is that giant truck. Until it finishes, JavaScript can’t do anything else - not even respond to your clicks. This is called blocking.

🚦 Helpers on the Side Road - Web APIs

Of course, if every long task blocked the road, the city (or the browser) would fall apart. That’s why the browser provides helpers, also known as Web APIs. They can take certain jobs off the main road and handle them separately.

Think of it like side roads with extra workers: one worker handles timers, another fetches data from the internet, another listens to clicks.

When you use something like setTimeout, you’re not asking JavaScript itself to wait. You’re handing that task to a helper on the side road.

console.log("Start");
setTimeout(() => console.log("Pizza ready!"), 2000);
console.log("End");
Enter fullscreen mode Exit fullscreen mode

Here’s what happens:

  • JavaScript logs “Start”.
  • It sees setTimeout, tells a helper: “Set a 2-second timer, and when you’re done, let me know.” Then it moves on.
  • It logs “End” immediately, without waiting.
  • Two seconds later, the helper finishes and says, “Pizza ready!”

This way, the main road is never blocked.

🚌 The Queue at the Bus Stop

Now here’s the catch: when helpers finish their work, they don’t just cut into traffic. Imagine if someone tried to shove their car right into the one-lane road while others were driving - chaos!

Instead, completed tasks go wait at a bus stop called the task queue. The event loop is like a traffic conductor who keeps asking:
“Is the road empty yet? Okay, let the next one from the bus stop in.”

That’s why even setTimeout(fn, 0) doesn’t run instantly. It’s not that JavaScript is slow - it’s just that the callback is patiently waiting its turn at the bus stop.

🎟️ VIPs in the Fast Lane : Microtasks

But every city has VIPs, right? In JavaScript, those VIPs are promises. They don’t wait at the normal bus stop. Instead, they get their own VIP queue called the microtask queue.

The event loop always gives priority to VIPs. No matter how many regular buses (setTimeouts) are waiting, if there’s even one VIP standing by, they get in first.

console.log("Start");

setTimeout(() => console.log("Regular task"), 0);

Promise.resolve().then(() => console.log("VIP task"));

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

The output here is:

Start  
End  
VIP task  
Regular task

Enter fullscreen mode Exit fullscreen mode

Even though the timeout had zero delay, the promise callback cut in line because microtasks always run before macrotasks.

📱 Async/Await – Ordering Food Delivery

Finally, let’s talk about async/await. Think of it like ordering food online. You place an order and then go about your life - scroll Instagram, reply to texts. When the delivery guy shows up, you pause, grab the food, and continue.

async function orderFood() {
  console.log("Placing order...");
  await new Promise(r => setTimeout(r, 2000));
  console.log("Food delivered!");
}
orderFood();
console.log("Chatting meanwhile...");
Enter fullscreen mode Exit fullscreen mode

The output is:

Placing order...  
Chatting meanwhile...  
Food delivered!

Enter fullscreen mode Exit fullscreen mode

That’s the beauty of await: it pauses only inside that function, without freezing the entire program.

📝 Wrapping It Up

The event loop isn’t magic. It’s just a system that makes sure JavaScript doesn’t freeze when doing multiple things at once.

  • The call stack is the one-lane road.
  • Heavy tasks are trucks that block it.
  • Web APIs are helpers with side roads.
  • Finished work waits at the task queue (bus stop).
  • Promises go to the microtask queue, a VIP lane.
  • The event loop is the conductor making sure traffic flows smoothly.

So next time your setTimeout(fn, 0) feels “late”, remember - it’s just waiting for the road to clear.

Happy Coding :) If you liked my content - do share it with others

Top comments (0)