Understanding the JavaScript call stack

Understanding the JavaScript call stack

This article would be focusing on explaining what the call stack is, and why it's important and needed by JavaScript.

Originally published by Johnson Ogwuru at dev.to

The JavaScript is a single-threaded, single concurrent language, meaning it can handle one task at a time or a piece of code at a time. It has a single call stack, which along with other parts constitutes the Javascript Concurrency Model (implemented inside of V8).

At the most basic level, the call stack is a data structure that utilizes the Last in, First out(LIFO) principle to store and manage function invocations.

Since the call stack is single, function execution is done one at a time from top to bottom, making the call stack synchronous. In managing and storing function invocations the call stack follows the Last in, First Out principle(LIFO) and this entails that the last function execution that gets pushed into the call stack is always the one to be cleared off, the moment the call stack is popped.

What purpose does the call stack serve in a JavaScript application? How does JavaScript make use of this feature?

When the JavaScript engine runs your code an execution context is created, this execution context is the first execution context that is created and it is called the Global Execution Context. Initially, this Execution Context will consist of two things - a global object and a variable called this.

Now when a function is executed in JavaScript (when a function is called with the () after its label), JavaScript creates a new execution context called the local execution context. So for each function execution, a new execution context is created

Just in case you were wondering, an execution context is simply put as the environment in which a JavaScript code is executed. An execution context consists of:

  • The thread of execution and
  • A local memory

Since JavaScript would be creating a whole bunch of execution contexts(or execution environments), and it has just a single thread, how does it keep track of which execution context its thread should be in and which it should return to? We simply say the call stack.

What happens is that, when a function is executed, and JavaScript creates an execution context for that function execution. The context execution is been pushed to the call stack. Now whatever is on top of the call stack is where the JavaScript thread would reside in. Initially when JavaScript runs an application and creates the global execution context, it pushes this context into the call stack and since it appears to be the only entry in the call stack, the JavaScript lives in this context and runs every code found there.

Now, the moment a function is executed, a new execution context is created, this time local, it is pushed into the call stack, where it assumes the top position and automatically, this is where the JavaScript thread would move to, running instructions it finds there.

JavaScript knows it's time to stop executing a function once it gets to a return statement or just curly braces. If a function has no explicit return statement, it returns undefined, either way, a return happens.

So the moment, JavaScript encounters a return statement in the course of executing a function, it immediately knows that's the end of the function and erases the execution context that was created and at the same time, the execution context that was erased gets popped off the call stack and the JavaScript thread continues to the execution context that assumes the top position.

To further illustrate how this works, let's take a look at the piece of code below, I would work us through how it is executed.

      function randomFunction() {
        function multiplyBy2(num) {
          return num * 2;
        }
        return multiplyBy2;
      }

  let generatedFunc = randomFunction();
  let result = generatedFunc(2);
  console.log(result) //4 

With the little function above, I would illustrate how JavaScript runs applications and how it makes use of the call stack.

The first time JavaScript runs this application if we remember the global execution context gets pushed into the call stack, for our function above the same thing happens, let's walk through it;

  1. The global execution context gets created and pushed into the call stack.
  2. JavaScript creates a space in memory to save the function definition and assign it to a label randomFunction, the function is merely defined but not executed at this time.
  3. Next JavaScript, comes to the statement let generatedFunc = randomFunction() and since it hasn't executed the function randomFunction() yet, generatedFunc would equate to undefined.
  4. Now, since JavaScript has encountered parenthesis, which signifies that a function is to be executed. It executes the function and from earlier we remember that when a function is executed, a new execution context is created, the same thing happens here. A new execution context we may call randomFunc() is created and it gets pushed into the call stack, taking the top position and pushing the global execution context, which we would call global() further down in the call stack, making the JavaScript thread to reside in the context randomFunc().
  5. Since the JavaScript thread is inside the randomFunc(), it begins to run the codes it finds within.
  6. It begins by asking JavaScript to make space in memory for a function definition which it would assign to the label multiplyBy2, and since the function multiplyBy2 isn't executed yet, it would move to the return statement.
  7. By the time JavaScript encounters the return keyword, we already know what would happen right? JavaScript terminates the execution of that function, deletes the execution context created for the function and pops the call stack, removing the execution context of the function from the call stack. For our function when JavaScript encounters the return statement, it returns whatever value it is instructed to return to the next execution context following and in this case, it is our global() execution context.

In the statement, return multiplyBy2, it would be good to note that, what is returned isn't the label multiplyBy2 but the value of multiplyBy2. Remember we had asked JavaScript to create a space in memory to store the function definition and assign it to the label multiplyBy2. So when we return, what gets returned is the function definition and this gets assigned to the variable generatedFunc, making generatedFunc what we have below:

      let generatedFunc = function(num) {
        return num * 2;
      };

Now we are saying, JavaScript should create a space in memory for the function definition previously knowns as multiplyBy2 and this time assign it to the variable or label generatedFunc.

In the next line, let result = generatedFunc(2), we execute the function definition which generatedFunc refers to (previously our multiplyBy2), then this happens:

  1. The variable result is equated to undefined since at this time the function it references hasn't been executed.
  2. JavaScript creates another execution context we would call generatedFunc(). When a local execution context is created, it consists of local memory.
  3. In the local memory, we would assign the argument 2 to the parameter num.
  4. Let's not forget, the local execution context generatedFunc() would get pushed into the call stack, and assuming the top position, the JavaScript thread would run every code found inside it.
  5. When JavaScript encounters the return statement, it evaluates num * 2, and since num refers to 2 stored initially in local memory, it evaluates the expression 22 and returns it.
  6. In returning the evaluation of the expression 22, JavaScript terminates the execution of the generatedFunc function, the returned value gets stored in the variable result then the call stack gets popped, removing the generatedFunc() context and getting the thread back to the global() context. So when we console.log(result), we get 4.

In conclusion:

The key things to take away from this article is that;

  • For every function execution, a new execution context is created, which gets popped into the call stack and is how the JavaScript thread learns which environment to take instruction from and execute.
Thank you for reading. If this article was helpful please give it some reactions and share, so others can find it. I will like to read your comments also.

credits to FreecodeCamp for the images used in this article

Originally published by Johnson Ogwuru at dev.to

===========================================

Thanks for reading :heart: If you liked this post, share it with all of your programming buddies! Follow me on Facebook | Twitter

Node.js 12 - The future of Server-side JavaScript

Understanding the Spread Operator in JavaScript

JavaScript Basics Before You Learn React

Google’s Go Essentials For Node.js / JavaScript Developers


javascript web-development

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

Hire Web Developer

Looking for an attractive & user-friendly web developer? HourlyDeveloper.io, a leading web, and mobile app development company, offers web developers for hire through flexible engagement models. You can **[Hire Web...

Why Web Development is Important for your Business

With the rapid development in technology, the old ways to do business have changed completely. A lot more advanced and developed ways are ...

Important Reasons to Hire a Professional Web Development Company

    You name the business and I will tell you how web development can help you promote your business. If it is a startup or you seeking some...

Hire Dedicated eCommerce Web Developers | Top eCommerce Web Designers

Build your eCommerce project by hiring our expert eCommerce Website developers. Our Dedicated Web Designers develop powerful & robust website in a short span of time.

How long does it take to develop/build an app?

This article covers A-Z about the mobile and web app development process and answers your question on how long does it take to develop/build an app.