The Fundamentals of Javascript’s CallStack
By: Ruben Vallejo
Tags: Begginer, Call Stack, Debugging, JavaScript

The Fundamentals of Javascript’s CallStack

The concept of executing code and the rules that a Javascript engine follows when executing code is an important one to understand, primarily because a programmer makes many assumptions when creating programs. As web programs are given functionality, these assumptions, if not tested, can and will eventually lead to bugs!!! In an attempt to lead us to a bug free utopia, let us better understand what the call stack is.

Every major web browser has a javascript engine that both executes and compiles code. Function invocation by this engine occurs synchronously, where it takes function calls one at a time and executes them from top to bottom. These processes are stored in a data structure called the call stack. Every data compiler has one, and it is here that the order of function calls are temporarily stored in memory until the calls are successfully executed and the task is completed.

So what exactly is the call stack and in what order do these tasks get completed?

MDN web docs describes the call stack as:

… a mechanism for an interpreter (like the JavaScript interpreter in a web browser) to keep track of its place in a script that calls multiple functions — what function is currently being run and what functions are called from within that function

The call stack, therefore, becomes inherently necessary when browsers are tasked with executing functions that have either callbacks or recursive calls to themselves within their function definition. The call stack helps manage function calls, and it temporarily stores the function’s information in memory until it is fully executed. Let us see the output of the following function invocation along with its call stack:

1. let thirdFunction = () => {

2. firstFunction();

3. console.log(“Hello from Third Function”)

4. }

5.

6. let secondFunction = () => {

7. console.log(“Hello from Second Function”)

8. }

9.

10. let firstFunction = () => {

11. console.log(“Hello from First Function”)

12. secondFunction()

13. }

14.

15. thirdFunction() output##======================================================>

Hello from First Function

Hello from Second Function

Hello from Third Function

In this example, the browser would read the three function definitions from top to bottom, starting from line 1 all the way to line 13; it would, however, not do anything because in javascript a function must be invoked in order for it to execute the code within its curly brackets. Once the interpreter reaches line 15 and sees a function call, the function called thirdFunction is stored temporarily in the structure called the call stack, along with its variables and code block.

CallStack: secondFunction

firstFunction

thirdFunction

Inside thirdFunction, there is a call to firstFunction, which would add that call above thirdFunction in the call stack and thus assign priority of execution to firstFunction. Inside firstFunction there is a call to secondFunction, which would then add the secondFunction above the firstFunction in the call stack and assign priority of execution to secondFunction. These priorities to execute occur because the call stack structure follows a rule where the latest addition to a stack will be the first to be completed.

After following the chain of calls we see that inside secondFunction there is a console.log which the call stack will take care to execute first. After completely resolving the secondFunction call, the call stack framework will discard the secondFunction call and move on down the list of stacks until everything called is resolved.

The best way to visualize this nesting of functions is to envision the song queue when you are out singing karaoke. Imagine, as people add to the list of songs that will be played throughout the night, the last song entered into the list will be the next song played. Throwing common courtesy aside, this is exactly how the call stack functions when there are function calls within other functions.

The Dangers of Stack Overflow Errors

A StackOverflowError is a runtime error where the amount of call stack memory allocated by the browser is exceeded. When the call stack exceeds, due to excessive, deep, or infinite recursion, a StackOverflowError is displayed.

If you ever find yourself stuck with an error like this one:

Uncaught Range Error: Maximum Call Stack Size Exceeded

Try looking over your recursive functions and check whether you have a break point anywhere in your code that would break you out of any recursive calls. This error is analogous to having a while loop that runs with a conditional statement that never equates to false, AKA. an infinite loop.

If you ever find yourself with a buggy code, test your assumptions. Opening code with a debugger by using the dev tools in your browser will give you access to your program’s call stack, under the sources tab. Here you can pause and see which function calls are queued up in your browser’s call stack, which may shed light on any annoyances hidden behind multiple function calls.

References: