DEV Community

Cover image for The Event Loop, Part II: The Wand Is Not Yours 🪄 (Or Why the UI Ignores You)
WebMagic
WebMagic

Posted on

The Event Loop, Part II: The Wand Is Not Yours 🪄 (Or Why the UI Ignores You)

Hey folks! 👋

If you missed the start of our journey, where we discussed why the browser lies to users to keep things looking smooth, check it out here 👉 Part I: The Illusion.

Today, we are ripping off the band-aid on a painful topic. The million-dollar question: If my code executes, why the hell doesn’t anything change on the screen?

Let’s be real: we all live in this illusion that JavaScript is in total control. But spoiler alert: the browser often just completely ignores your commands.

The Illusion We Don't Notice 🙈

We are used to writing code with the expectation of "instant karma":
🪄 I changed the DOM — show it.
🪄 The Promise resolved — render the update!
🪄 This line ran — the UI must reflect it.

But it doesn't work like that. JavaScript can change the DOM. But only the Browser decides whether to show those changes.

It's like ordering a pizza: you can place the order (change state), but that doesn't mean the delivery driver (the renderer) is ringing your doorbell right now.

The Browser is Not Just a JS Runtime 🏗️

Modern Chrome or Firefox isn't just a "JavaScript environment." It’s a complex machine where multiple systems work in parallel:

🧩 JS Engine (V8) — executes your code.
🧩 Rendering Engine (Blink) — paints the pixels.

Think of them as neighbours shouting over a fence. They are not the same person. And most importantly: They share the same Main Thread.

Aunt Petunia’s Experiment 🐸

Let’s get to the code. Imagine a classic frontend scenario:

User clicks a button.
We show a loading spinner.
We run a heavy synchronous task (like parsing a massive JSON).
We hide the spinner.

Expectation: The spinner appears, spins for a bit, and vanishes. Reality: ... 🫠

button.addEventListener("click", () => {
  showMagicLoader(); // 🪄 Spell: "Show the spinner!"

  // ⚠️ Warning! Heavy synchronous work.
  // We are blocking the Main Thread completely.
  const response = "[" + "1,".repeat(5_000_000) + "1]";
  JSON.parse(response); // The browser is frozen here 🥶

  hideMagicLoader(); // 🪄 Spell: "Hide the spinner!"
});
Enter fullscreen mode Exit fullscreen mode

What does the user see? Absolutely nothing. The screen just "freezes" for a second and then "unfreezes." The spinner never appeared.

Honesty Check 🔦: did the thought cross your mind that the spinner would appear for at least a millisecond?

If yes — congratulations, you’re a normal developer 😅. I used to think that too. But here is the harsh truth:

Code Execution ≠ Rendering

While JavaScript is busy dealing with your JSON on the Main Thread, the browser physically cannot paint anything. It is blocked. When JS finally finishes the job, it immediately executes hideMagicLoader().

To the browser, the timeline looks like this:
"Oh, JS changed the DOM to show a spinner... but I'm busy executing JS, I'll wait."

"Yup, JS is still going..."
"Oh, JS now says to hide the spinner. Okay."

Result: The spinner existed in the DOM, but it never made it to the Paint stage.

It’s Not a Bug, It’s a Feature (Seriously) 😎.
Browsers aren't optimised for us developers. They are optimised for users. If a state appears and disappears within a single synchronous task (one "tick"), blocking the thread, the browser simply discards it to save resources. Efficient? Yes. Confusing? You bet.

TL;DR / The Takeaway 🎯

Your mental model needs a shift:

JavaScript controls STATE.
The Browser decides REALITY (Rendering).

The illusion breaks when we assume: "If the code ran, the user saw it." This is the curse that leads to "janky" interfaces.

What’s Next? ✨

In the next part (Part 3), we are going to get properly under the hood. 🧱 Call Stack 🧵 Main Thread ⏳ Synchronous Execution

We’ll break down exactly where JS lives, and why—before you can understand the Event Loop—you have to understand "The Queue."

💬 Question for the community:

We have all accidentally "crashed" a browser tab with an accidental infinite loop or heavy recursion. What was the specific operation that first made you realize JS blocks the interface? Drop your stories (and failures) in the comments, let's laugh about it together! 👇

Happy coding! 👩‍💻✨

Top comments (0)