JavaScript: Event Loop, Web APIs, Task Queue

Hoang Vu,3 min read

March 23, 2026

Have you ever wondered how JavaScript — a single-threaded language — can handle thousands of requests simultaneously without "freezing"? The answer doesn't lie within the language itself, but within the JavaScript Runtime Environment.

Let's peel back each layer of this "onion" named Event Loop through the visual simulations below.

Javascript Runtime Environment
Call Stack
Web APIs
Task Queue
Microtask Queue
Event Loop

1. Call Stack: The Heart of Execution

The Call Stack is a LIFO (Last In, First Out) data structure. It tracks which function is currently being executed.

How it works:

  1. When you call a function, it gets "pushed" onto the stack.
  2. The interpreter executes that function.
  3. When the function returns a result or finishes, it gets "popped" off the stack.
Runtime Visualizer
Step 0/10
Source Code
Editor
1234567891011
Call Stack (LIFO)
Stack Empty
Live Console
Trạng thái luồng:
IDLE
Mô tả cơ chế:
Chờ thực thi...

2. Web APIs: The Browser's Extended Arm

The JavaScript Engine (like V8) does not work alone. The browser provides Web APIs to handle time-consuming tasks like HTTP Requests, Timers, or DOM events.

JS Engine (Stack)
Web APIs (Browser)
Task Queue

What actually happens? JavaScript pushes setTimeout onto the Call Stack -> Realizes it's a Web API -> Hands it over to the Browser to manage the timer -> setTimeout pops off the stack immediately. Execution continues without waiting. When the timer ends, the Browser pushes the Callback into the Task Queue.


3. The "Queuing" Process: Task Queue & Microtask Queue

After the Browser finishes a task (for example, counting 2 seconds or receiving data from an API), it cannot arbitrarily jump into the Call Stack. It has to wait in a queue.

Task Queue (Macrotask Queue)

Used for: setTimeout, setInterval, setImmediate, I/O tasks.

Microtask Queue (Higher Priority)

Used for: Promises, async/await, process.nextTick, MutationObserver.

Golden Rule: The Event Loop will prioritize clearing the ENTIRE Microtask Queue before picking A SINGLE task from the Task Queue.

Microtask Queue
(VIP)
Promise 1
Promise 2
Task Queue
(Macro)
setTimeout
Call Stack Execution
Ready

4. Event Loop: The Dedicated Coordinator

The Event Loop has only one job: Checking the Call Stack. If the Call Stack is empty, it will take a task from the queue and push it onto the Stack for execution.

Task Queue
task 1
task 2
Done!
Call Stack
Stack Empty
STEP 1: Check Stack Empty
STEP 2: Take Task From Queue
STEP 3: Push Task to Stack
STEP 4: Wait For Task Finish

The 4-step Process:

  1. Check Stack Empty: Wait until there are no functions running.
  2. Handle Microtasks: Prioritize clearing the entire Microtask Queue.
  3. Pick Macrotask: Take only 1 Macrotask from the Task Queue.
  4. Push to Stack: Push the task onto the Stack for the Engine to execute.

5. Why should you care?

Understanding the Event Loop helps you avoid "disastrous" performance bugs:

  1. Don't block the Main Thread: Don't run heavy algorithms (like image processing, large number calculations) directly on the Call Stack. Use Web Workers.
  2. Execution Order: Know exactly when data from an API will be processed.
  3. Prioritize Microtasks: Use queueMicrotask() if you need a task to run right after the current code but before the Browser re-renders the UI.

Summary in 30 seconds:

  • Stack: Where code executes immediately.
  • Web API: Where asynchronous tasks "temporarily reside".
  • Microtask Queue: The "VIP" Queue (Promise).
  • Task Queue: The "Normal" Queue (setTimeout).
  • Event Loop: The gatekeeper, only opens the door to push queues into the Stack when the Stack is completely empty.

Hope this article helps you "decode" the magic behind how JavaScript operates!

2026 © @hoag/blog.