JS Concepts: Call Stack

Today, we’re going to find out what is a call stack and how it works in JavaScript.

What is a call stack

We can say that in JavaScript, the call stack is a kind of a to-do list of function invocations. It is a structure that stores a list of functions to be called.

The reason why we call it a call stack is because it stores data in a stack. Stack is an abstract data type where elements are inserted and removed according to the Last-In First-Out (LIFO) principle.

It’s like a stack of pancakes; you always add to the top of the stack and remove from the top of the stack


how the stack works


Because JavaScript is mainly single threaded, it can only execute one line of code at any given time. Basically, it can only do one thing at a time.

If in a JavaScript application, you call a function, that function may resolve in any other function calls. Those functions may be waiting on results of other calls before the main function finishes. So the application needs to keep track of things that were invoked and things that are waiting to be returned. It needs to keep a history of functions that were invoked but are not done yet.

How it works

Whenever you call a function, the details of the call are saved on top of the stack. Whenever a function returns, the information is taken off the top of the stack.

The code execution is synchronous. Whenever JavaScript engine finds a function invocation, it creates a new execution context for that function and pushes it to the top of the stack. The call stack knows the next function to be executed and will remove it after execution. It reaches to the context below it in the current stack until the memory is clear.

Let’s look at the example:

function foo() {
    console.log('Hello')
}

function bar() {
    foo()
    console.log('World')
}

bar()

This is what happens if you run this code:

  • function bar() is called; empty stack frame (execution context) is created;

Call Stack:
> bar()

  • function bar() calls function foo() which is added to the top of the stack

Call Stack:
> foo()
bar()

  • function foo() returns and prints ‘Hello’ to the console
  • function foo() is removed from top of the stack

Call Stack:
> foo()
> bar()

  • now, function bar() is executed and it returns, ‘World’ is printed to the console
  • function bar() is popped off the stack

Call Stack:
> bar()

  • we ended up with an empty stack, the memory is cleared

Call Stack:
EMPTY


You can also observe this if your browser throws an error stack trace in the console. It indicates where in the function it failed. Executed functions are presented from top to bottom, like in the stack. See the example below.

Error stack trace


Stack overflow

We’ve all been there… This happens when we run an infinite loop.

A function invocated recursively (a function calls itself) can hit a limit on the size of the stack in a browser. That’s what we call stack overflow. If this happens, a browser will stop all calls and throw ‘Maximum call stack size exceeded’ error.

RangeError: maximum call stack exceeded


Summary

Call stack is an ordered set of stack frames where:

  • most recently executed function is at the top of the stack
  • the first invoked function is at the bottom of the stack
  • the stack is processed from top to bottom

Other takeaways are:

  • JavaScript is single threaded, it can only do one thing at a time
  • Stack is a data structure where you always add to the top of the stack and remove from the top of the stack (LIFO)
  • Function execution is synchronous



This site owned by Mateusz Janusz who is a software engineer living in Warsaw, Poland. He sometimes writes here about things that he is interested in. You can also find him at Github, LinkedIn, Medium and Dev.to.