logo
banner
Photo by MARIOLA GROBELSKA on Unsplash

JavaScript’s Event Loop — Explained Like You're Five (But With More Sarcasm)

So you're building a web app, and suddenly your async functions start behaving like rebellious teenagers — returning whenever they feel like it. Congratulations, you’ve met the JavaScript Event Loop. It’s the unsung hero (or sneaky villain) of your code's execution. Let’s dive into it.


🧠 First, a Little Brain Primer: JavaScript Is Single-Threaded

Imagine JavaScript as a cook in a small kitchen with one burner. That’s right, it can only cook one dish at a time. If you ask it to make toast, brew coffee, and flip pancakes, it has to queue those tasks. Multitasking? Pfft. JavaScript is more of a "brb, doing this one thing first" kinda guy.

But... JavaScript is weirdly fast, and can handle lots of tasks at once — or so it seems. The trick? It's all about asynchronous operations and the event loop.


🏗️ Stack, Queue, and Web APIs — The Cast of Characters

Before we talk about the Event Loop itself, let’s meet the team:

1. Call Stack (a.k.a. “The Do-Right-Now Zone”)

The Call Stack is where functions go to get executed. It’s LIFO (Last In, First Out) — think of it as a stack of pancakes, where the last one you put on is the first one you eat. Yum.

function sayHi() { console.log("Hi!"); } sayHi(); // Goes on the stack, gets executed, gets popped off.

Easy peasy. But what if we add:

setTimeout(() => { console.log("Hello after 0ms"); }, 0);

Hold on... 0ms?! That should run immediately, right?

Wrong. This is where Web APIs and the Event Loop pull off their little magic trick.

2. Web APIs (a.k.a. “The Outsourcing Department”)

When you use setTimeout, fetch, or DOM events, you’re not dealing with core JavaScript anymore. These are browser-provided APIs (also available in Node.js through different means). JavaScript offloads tasks to them — like giving your assistant a to-do list and going back to binge Netflix (or run more code).

3. Callback Queue (Task Queue) (a.k.a. “The Waiting Room”)

Once the Web APIs finish their job — say, your timer is up — they dump the callback into the Callback Queue, where it patiently waits to be noticed by the Event Loop like an intern waving for coffee orders.


🔁 Enter the Event Loop

Imagine a tiny robot constantly checking:

That’s the Event Loop. It’s a bouncer at an exclusive club (the call stack), letting in callbacks only when there’s room.


🔬 Let’s Visualize It (in Code)

console.log("Start"); setTimeout(() => { console.log("Timeout callback"); }, 0); Promise.resolve().then(() => { console.log("Promise microtask"); }); console.log("End");

Output?

Start End Promise microtask Timeout callback

Wait, WHAT? Isn’t 0ms faster than a promise?

Ah, my young padawan, welcome to the dark arts of the Microtask Queue.


⚡ Microtasks vs. Macrotasks: The Plot Thickens

There’s another queue: the Microtask Queue.

After each turn of the event loop, the engine:

  1. Executes all microtasks 🧠

  2. Then checks the callback queue 🧾

So in our code above:

The event loop is like: “Okay, before I do anything else, let me finish these tiny tasks. Then I’ll get to the big stuff.”


💡 So Why Does Any of This Matter?

Because understanding the event loop saves lives (okay, maybe just your sanity). Here’s when it’s crucial:


🧪 Bonus: Block the Stack and See the Chaos

setTimeout(() => console.log("I'm late!"), 0); for (let i = 0; i < 1e9; i++) {} // Block the stack console.log("Done blocking");

Even though the timer says "0ms", it runs after the big loop finishes. Why? Because the call stack was busy — the Event Loop couldn't slip anything in.


🎯 TL;DR (Too Long; Debugged Recently)


🧠 Final Thoughts

Understanding the Event Loop is like knowing how the magician pulls off the trick. It doesn’t make the show any less fun — but it does make you better at building the show.

Now go forth and write better asynchronous code — and maybe tell setTimeout to chill once in a while.