DEV Community

Cover image for Understanding Call Stack, Callback Queue, Event Loop, and Microtask Queue in JavaScript
gautam kumar
gautam kumar

Posted on

1

Understanding Call Stack, Callback Queue, Event Loop, and Microtask Queue in JavaScript

JavaScript is known for its single-threaded, non-blocking nature, which is made possible by the efficient coordination of the call stack, callback queue, event loop, and microtask queue. If these terms sound confusing, don’t worry! In this blog, we’ll break them down with beginner-friendly explanations and examples.

1. Call Stack

The call stack is like a "to-do list" that JavaScript uses to keep track of function execution. It manages the order in which functions are called and ensures they run one at a time in a synchronous manner.

How it works:

  • When a function is called, it gets added (or "pushed") to the top of the stack.
  • Once the function finishes executing, it is removed (or "popped") from the stack.

Example

function fun() {
  console.log("Hello!");
}

function check() {
  console.log("Goodbye!");
}

fun();       // ADDED TO THE STACK, EXECUTED, THEN REMOVED 
check();  // ADDED TO THE STACK, EXECUTED, THEN REMOVED
Enter fullscreen mode Exit fullscreen mode

Output
Hello!
Goodbye!

Here, each function is executed one at a time, in the order they’re called.

2. Callback Queue

The callback queue holds tasks (like callbacks from setTimeout) that need to be executed after the call stack is empty. These tasks are asynchronous and wait their turn to be processed.

How it works:

  • When an asynchronous operation (e.g., setTimeout) completes, its callback is sent to the callback queue.
  • The event loop ensures these tasks are executed only when the call stack is empty.

Example:

console.log("Start");

setTimeout(() => {
  console.log("Inside setTimeout");
}, 1000);

console.log("End");
Enter fullscreen mode Exit fullscreen mode

Output:
Start
End
Inside setTimeout

Here’s what happens:

“Start” and “End” are logged immediately because they’re in the call stack.

setTimeout schedules a callback to run after 1 second, placing it in the callback queue.

After the call stack is empty, the event loop moves the callback from the queue to the stack for execution.

3. Event Loop

The event loop is the unsung hero that coordinates the execution of JavaScript code. It ensures the call stack, callback queue, and microtask queue work seamlessly together.

Image description

How it works:

  • The event loop checks if the call stack is empty.
  • If the stack is empty, it processes tasks from the microtask queue (if any) and then from the callback queue.
  • This process continues indefinitely, ensuring tasks are executed in the correct order.

4. Microtask Queue

The microtask queue is similar to the callback queue but with higher priority. It holds tasks such as Promise callbacks and MutationObserver callbacks. Microtasks are executed before any tasks in the callback queue.

How it works:

After the call stack is empty, the event loop processes all microtasks before moving on to the callback queue.

Example:

console.log("Start");

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

Promise.resolve().then(() => {
  console.log("Inside Promise");
});

console.log("End");
Enter fullscreen mode Exit fullscreen mode

Output:
Start
End
Inside Promise
Inside setTimeout

Here’s why:

  • "Start" and "End" run first because they’re synchronous.
  • The promise’s .then() callback is added to the microtask queue.
  • The setTimeout callback is added to the callback queue.
  • The event loop processes the microtask queue (Promise) before the callback queue (setTimeout).

Lets Summarize this

JavaScript handles asynchronous operations using the call stack, callback queue, event loop, and microtask queue. The call stack runs synchronous code, while the event loop coordinates asynchronous tasks. Promises (microtask queue) are prioritized over setTimeout callbacks (callback queue), ensuring efficient and orderly execution of code.

Top 10 Interview Questions

Here’s a set of 10 most-asked interview questions related to the topics of the call stack, callback queue, event loop, and microtask queue in JavaScript.

1. What is the call stack in JavaScript, and how does it work?
Answer:
The call stack is a data structure that keeps track of function execution in JavaScript. It follows the Last In, First Out (LIFO) principle:

  • When a function is called, it is pushed onto the stack.
  • When the function execution completes, it is popped off the stack.

2. What is the role of the callback queue in JavaScript?
Answer:
The callback queue holds tasks (callbacks) from asynchronous operations, like setTimeout or event listeners, that are ready to be executed after the call stack is empty.

3. What is the event loop, and why is it important?
Answer:
The event loop is a mechanism that continuously checks whether the call stack is empty. If it is, the event loop pushes tasks from the callback queue or microtask queue onto the stack for execution. It enables JavaScript to perform non-blocking operations in a single-threaded environment.

4. What is the microtask queue, and how is it different from the callback queue?
Answer:
The microtask queue holds high-priority tasks such as Promise resolutions and MutationObserver callbacks. These tasks are executed before any task in the callback queue.

5. How does setTimeout work in JavaScript?
Answer:
setTimeout schedules a callback to execute after a specified delay. The callback is added to the callback queue and waits for the event loop to push it to the call stack after the delay.

6. Why does Promise execute its .then() before setTimeout?
Answer:
The .then() of a Promise is a microtask, which is handled before any tasks in the callback queue, including setTimeout. This prioritization ensures that critical tasks like Promises are handled promptly.

7. What happens if a microtask continuously queues another microtask?
Answer:
If a microtask queues another microtask, it creates a loop where the event loop keeps executing microtasks indefinitely before moving to the callback queue. This can cause a delay in executing tasks in the callback queue.

8. What is the difference between synchronous and asynchronous code in JavaScript?
Answer:
Synchronous code is executed sequentially, blocking subsequent tasks until the current task is completed.
Asynchronous code allows other tasks to run while waiting for operations like I/O or timers. Callbacks handle the result when the operation completes.

9. Can you explain the order of execution in the following code?

console.log("A");
setTimeout(() => console.log("B"), 0);
Promise.resolve().then(() => console.log("C"));
console.log("D");
Enter fullscreen mode Exit fullscreen mode

Answer:

  • “A” and “D” are synchronous and executed first.
  • The .then() callback is a microtask, so “C” is executed next.
  • The setTimeout callback is in the callback queue, so “B” is executed last.

Output:
A
D
C
B

10. What is the difference between blocking and non-blocking code in JavaScript?
Answer:
Blocking code prevents further execution until it completes. Example: a while loop that runs indefinitely.
Non-blocking code allows other tasks to execute while waiting for a task to complete. Example: setTimeout or fetch operations.

These questions and answers will help you master the foundational concepts of JavaScript's execution model and confidently tackle technical interviews.

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (1)

Collapse
 
sibasis_padhi profile image
Sibasis Padhi

Nice article with interview questions.

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more