🧠 Deep Dive into the JavaScript Call Stack: Beginner to Advanced

krishankrishan
4 min read

When you're writing JavaScript code, you're interacting with one of the most fundamental components of the JavaScript engine β€” the Call Stack. Whether you're new to programming or brushing up for interviews, understanding the Call Stack is crucial to mastering JavaScript's execution model.


πŸ“Œ What Is the Call Stack?

The Call Stack is a mechanism that keeps track of function calls. It works just like a stack of plates β€” Last In, First Out (LIFO).

  • When a function is called, it's added to the top of the stack.

  • When the function completes, it's removed from the stack.

Let’s visualize this with a simple example:

jsCopyEditfunction greet() {
  console.log("Hello!");
}

function startApp() {
  greet();
  console.log("App started");
}

startApp();

🧱 Call Stack Process:

  1. startApp() is called β†’ pushed to the stack.

  2. Inside startApp, greet() is called β†’ pushed to the stack.

  3. greet() logs β€œHello!” β†’ popped from the stack.

  4. Execution resumes in startApp β†’ logs β€œApp started” β†’ popped from the stack.


πŸ§ͺ Visualization:

yamlCopyEditInitially:       []

After startApp:  [startApp]

Inside startApp: [startApp, greet]

After greet:     [startApp]

After log:       []

⚠️ Stack Overflow

What happens if the stack keeps growing without clearing? That’s a Stack Overflow!

jsCopyEditfunction crash() {
  crash(); // Infinite recursion
}

crash(); // πŸ’₯ RangeError: Maximum call stack size exceeded

This happens because crash() keeps calling itself and never gets removed from the stack.


🚦 How It Works with the Event Loop (Short Teaser)

The Call Stack works in tandem with:

  • Web APIs: Browser-provided features (e.g., setTimeout, fetch)

  • Callback Queue: Holds messages to process

  • Microtask Queue: Holds promises and queueMicrotasks

  • Event Loop: Decides what goes from queue to stack next


πŸ” Interview Insight

Q: What is the Call Stack, and how does it relate to asynchronous code?

A: The Call Stack is where synchronous code executes. Asynchronous tasks are handled outside the stack (in Web APIs) and are pushed back in via the Event Loop once the stack is empty.

Understanding the Components of the Event Loop System

The Event Loop System in JavaScript handles asynchronous code execution. It allows JavaScript β€” a single-threaded language β€” to be non-blocking and handle events like setTimeout, fetch, or DOM interactions efficiently.

πŸ”§ Components of the Event Loop:

  1. Call Stack

  2. Web APIs

  3. Callback Queue (Task Queue)

  4. Microtask Queue

  5. Event Loop


🌐 2. Web APIs (Browser or Node APIs)

When you call a function like setTimeout, it doesn’t go to the stack. Instead, it gets handed off to a Web API (like setTimeout, fetch, or DOM Events).

jsCopyEditconsole.log('Start');

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

console.log('End');
  • 'Start' β†’ logged immediately.

  • setTimeout is passed to the Web API β†’ a timer is started.

  • 'End' β†’ logged immediately.

  • When the timer finishes, the callback (console.log('Inside Timeout')) is sent to the Callback Queue.


πŸ“₯ 3. Callback Queue (aka Task Queue)

This is where tasks like setTimeout, setInterval, and DOM event handlers wait after finishing in Web APIs.

The Event Loop checks if the Call Stack is empty, then pushes these callbacks onto the stack.


⚑ 4. Microtask Queue

Contains Promises, queueMicrotask, and MutationObserver.

jsCopyEditconsole.log("Start");

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

console.log("End");

πŸ‘‰ Even though no timeout, the Promise callback runs after the stack is clear and before any setTimeout.

Microtasks always get higher priority than Callback Queue.


πŸ” 5. Event Loop (The Traffic Controller)

  • Constantly monitors the Call Stack and the Queues.

  • If the stack is empty:

    • It first processes all microtasks (in order).

    • Then it picks a task from the Callback Queue (if any).


πŸ§ͺ Code Demonstration

jsCopyEditconsole.log("Start");

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

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

console.log("End");

βœ… Output:

javascriptCopyEditStart
End
Promise
setTimeout

✍️ Written by Krishan β€” follow me on Twitter and GitHub and Linkedin

πŸ’‘ Check out the current code examples and notes repo: GitHub

πŸ“ Read more on my blog: Hashnode

10
Subscribe to my newsletter

Read articles from krishan directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

krishan
krishan

πŸ‘‹ Hey, I'm a Frontend Developer passionate about building clean, user-friendly interfaces. πŸš€ Learning and sharing everything from React, JavaScript, HTML/CSS to advanced topics like Data Structures, Algorithms & System Design. πŸ’» Documenting my journey from fundamentals to becoming a top-tier developer β€” one blog at a time. πŸ“š Join me as I break down complex topics into easy, practical lessons β€” with GitHub repos, code snippets, and real-world examples. πŸ” Consistent growth, community learning, and aiming high!