Back to List

Event Loop β€” How JavaScript Handles Asynchronicity

Explains the operating principle of the JavaScript event loop, the relationship between the call stack and the task queue, and the priority of microtasks.

Intermediate
|
5min
|
Verified (2026-07)
Progress0/55 (0%)

Event Loop β€” How JavaScript Handles Asynchronicity

After finishing this topic

You will understand the principle of how JavaScript can handle asynchronicity while being single-threaded.


How can it be single-threaded?

JavaScript executes only one task at a time. It's single-threaded. However, it handles timers, network requests, and click events concurrently. How?

The secret lies in the Event Loop. The JavaScript engine (V8) doesn't do it alone. The browser (or Node.js) helps.


Three Components

Call Stack: This is where currently executing functions are stacked. When a function is called, it's added to the stack, and when its execution finishes, it's removed. It follows a LIFO (Last In, First Out) structure.

Web API: These are features provided by the browser. They include setTimeout, fetch, and DOM event listeners. They operate outside the JavaScript engine.

Task Queue: This is the queue where callbacks completed by the Web API wait. When the call stack is empty, one by one, they are taken out from here and executed.


Execution Flow

javascript
console.log("1");

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

console.log("3");

Output: 1, 3, 2.

Even though it's a 0ms timer, "2" is printed last. Following the flow:

  1. console.log("1") β†’ Executed in the call stack β†’ Output
  2. setTimeout β†’ Registers a timer in the Web API β†’ Removed from the call stack
  3. console.log("3") β†’ Executed in the call stack β†’ Output
  4. The call stack is empty β†’ The event loop checks the task queue β†’ Executes the callback β†’ Prints "2"

setTimeout(fn, 0) means "execute when the call stack is empty," not "execute immediately."


Microtask Queue

The .then() of a Promise goes into the Microtask Queue, not the task queue. Microtasks are executed before tasks.

javascript
console.log("1");

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

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

console.log("4");

Output: 1, 4, 3, 2.

When the call stack is empty, the event loop:

  1. First, empties the entire microtask queue (Promise callbacks)
  2. Then, takes one from the task queue (setTimeout callback)

async/await also uses Promises internally, so it's a microtask.


If the Call Stack is Occupied for a Long Time

javascript
while (true) {
  // Infinite loop
}

If the call stack is not empty, the event loop will not run. Clicks will not respond, and timers will not execute. The browser will display "This page is not responding."

If you need to perform heavy calculations, use Web Worker or break down the work so that the call stack is cleared periodically.


Key Points

JavaScript is single-threaded, but it handles asynchronicity using the browser's Web API and the Event Loop. setTimeout(fn, 0) means "execute when the call stack is empty." Microtasks (Promises) are always executed before tasks (setTimeout).

πŸ’¬ Questions & Comments

0 comments

You can post without signing in. Guest comments cannot be edited or deleted by their author.

0/2000

Loading...