JavaScript Node.js V8

The JavaScript Event Loop: A Visual Guide

ET
Emma Taylor
Frontend Architect
Nov 25, 2025
15 min read

What You'll Learn

How JavaScript handles asynchronous operations using a single thread. Understand the V8 engine, Call Stack, Web APIs, Task Queue, Microtask Queue, and the Event Loop.

The Single-Threaded Nature of JS

JavaScript is a single-threaded, non-blocking, asynchronous, concurrent language. What does that mean? It means JS has exactly one Call Stack and can only do one thing at a time. If a function takes 5 seconds to run, the browser freezes for 5 seconds.

So how can Node.js handle millions of concurrent HTTP requests without freezing? The answer is the Event Loop.

The Browser / Node.js Environment

The JavaScript engine (like V8 in Chrome/Node) doesn't run in isolation. The environment provides extra tools:

1. The Call Stack

Where functions go to be executed. Last-In-First-Out (LIFO).

2. Web APIs / C++ APIs

Extra features provided by the browser/Node (e.g., setTimeout, DOM, fetch/HTTP requests, fs modules).

3. Callback Queue (Task Queue)

Where asynchronous callbacks (like a completed setTimeout) wait to be executed. First-In-First-Out (FIFO).

4. Microtask Queue

High priority queue specifically for Promises (e.g., .then()). Executes before the Callback Queue.

The Event Loop's Only Job

The Event Loop is a continuous loop that checks two things:

while (queue.waitForMessage()) {
  1. Is the Call Stack empty?
  2. If yes, take the first thing in the Microtask Queue and push it to the stack.
  3. If Microtasks are empty, take the first thing in the Callback Queue and push it to the stack.
}

The Classic Interview Question

What is the output of the following code?

javascript — Event Loop Test
console.log("1");

setTimeout(function() {
  console.log("2");
}, 0);

Promise.resolve().then(function() {
  console.log("3");
});

console.log("4");

Step-by-Step Execution:

  1. console.log("1") goes on the stack. Prints 1. Pops off.
  2. setTimeout goes on the stack. It's a Web API, so the browser takes it and starts the 0ms timer. The callback function is immediately pushed to the Callback Queue.
  3. Promise.resolve() creates a resolved promise. Its .then() callback is pushed to the Microtask Queue.
  4. console.log("4") goes on the stack. Prints 4. Pops off.
  5. The script finishes. The Call Stack is now empty.
  6. The Event Loop checks the Microtask Queue first. It finds the Promise callback, pushes it to the stack. Prints 3.
  7. The Event Loop checks the Microtask Queue again. It's empty. It checks the Callback Queue. Finds the setTimeout callback. Prints 2.

Output: 1, 4, 3, 2

Why node.js can be blocked

If you run a heavy computation (like an infinite while loop or a massive JSON parse) on the main thread, the Call Stack never empties. The Event Loop gets stuck, and your server won't be able to process any new incoming HTTP requests. Always offload heavy CPU tasks to Worker Threads!

Keep Reading

D
DevOps

Docker Networking Demystified: Bridge, Host & Overlay

8 min read Read More
C
Cloud

AWS IAM Roles vs Users vs Policies

10 min read Read More
P
Programming

Understanding Python's GIL & Multiprocessing

14 min read Read More