Javascript under the hood feat. Execution Context and Call stack

Javascript under the hood feat. Execution Context and Call stack

An effort to make Execution Context and Call stack easy to understand for fellow beginners.

Hello there ๐Ÿ–

By the end of this blog, you will understand how is JS code executed in the browser. We will talk about the following topics:

  • Execution Context

  • Call Stack

So, let's get started and discuss it.

Execution Context

Every JS file has several lines of code, organized with the help of variables, data structures, functions, and many more. The code is straightforward. However, behind the scene, JavaScript does many things.

We all must have heard that

Everything in JavaScript happens inside an Execution Context.

But what is this Execution Context? Let me help to make it simple for you. A Lexical Environment determines how and where we write our code physically. Note that there is more than one Lexical Environment in code, but not all Lexical Environment get executed at once. When the JS engine executes a code, it creates an execution context. The execution context is the environment where a specific portion of the code executes.

Each execution context has 2 phases - the memory creation phase and the execution phase. These might seem some heavy topics but actually, they are pretty easy to learn.

Let me make you absorb this. Think it in a way that our code may or may not be written in a sequence. Some portion may in at the start of the code, or at the very end, or somewhere in the middle, but the actual sequence of code is in what order it is required or called by the compiler or engine. The order of lexically written code and order of execution is not the same. The order in which the code is executed/run by the system is Execution Context.

Execution Context.png

Global Execution Context

When a script is executed the first time, the Global execution context is created by Javascript Engine. It has 2 phases

  1. Memory Creation Phase
  2. Execution phase

Creation Phase

In the creation phase, two unique things get created:

  • A global object called WINDOW( in browser).
  • A global variable called THIS.

Now let's figure out what happens when we open and execute JS files in a browser. Now here is the twist, even when we Execute an empty file Execution context is generated. I will try to explain this with the help of the below example.

The shortest Javascript program ever.(File is Empty )

  1. The Global Execution Context gets created when we load the JavaScript file, even when it is empty.
  2. It creates 2 special things -
    • window object

value of window value of window.png

  • this

value of this

value of this.png

  1. For an empty file window and this are equal.

    window===this //true

  2. As the file is empty, there is no execution phase here.

When executes a file with variable and functions:

Wherever variables are declared, memory is created for the following variable. Variable gets initialized with a unique value undefined. There is a difference between not defined and undefined. here the variables are given memory but no value is defined to it, that's why undefined.

If there is a function, then it gets placed directly into the memory, consider that the function copied as it is in memory. For every function in the program, a separate Function Execution Context(FEC) is created. We will talk about it below. When FEC is created, the control is passed to the newly created FEC.

Execution Phase

The code execution starts in this phase. During the execution phase, the JavaScript engine executes the code line by line. Values are assigned to variables and functions are called. The call stack, which is empty now has GEC at its top as it is pushed when the execution starts.

Remember, during the creation phase functions are already stored in the memory.

Now for every function call, the javascript engine creates another Function Execution Context separately. Always keep in mind that

Javascript is a "synchronous single-threaded" language. So not more than one execution can happen at a given time.

Function Execution Context

Whenever we invoke a function, a Function Execution Context(FEC) gets created. Function Execution Context is similar to Global Execution Context and has 2 phases same as Global one - creation and execution. The FEC is similar to GEC and has access to a special value called arguments but instead of a global object, it creates an arguments object.

Argument Object refers to all the parameters passed to the function.

These are points that we need to understand here.

  1. All the variables and functions in the GEC are still accessible.
  2. When a function calls another function, a new function execution context gets created for the newly called function called and each FEC has its scope of variables.
  3. Once the execution phase of the current FEC is over, it returns the control to the Execution Context where it was called.

CALL STACK

To keep a track of all the GEC and FEC, the JS engine uses a data structure called CALL STACK. Stack-based on LIFO (last-in-first-out) principle is used to manage execution contexts and their functioning. Let us discuss the operation performed by call stack maintained by JS engine:

  1. At first the stack is empty.
  2. When we execute a script, The GEC is created. So it is pushed to the top of the stack.
  3. Now whenever a function is called, FEC is created for respective function and it is pushed to the top of a stack and starts executing the function. If the function calls another function, then another FEC is created for the called function, pushed to the top of the stack, and executed first.
  4. When the execution of the function is complete, the JS engine pops the FEC off the stack and executes the FEC at the top of the call stack.
  5. When the stack is empty the execution stops.

Stack overflow

The size of the stack is fixed depending on various factors. If the number of Execution Context exceed the stack size, Stack overFlow occur.

When a recursive function with no exit condition is called.

Code.JPG

Xjkh5YkSm (1).jpg

For this example, the var n, var double1, and var double2 are given memory, and function double() is copied to the memory as it is. Global Execution Context is pushed to the top of the empty stack

memory_creation.jpg

After creating memory, the values are assigned to variables in this phase. Here n=2, that means n is assigned 2 as value. Also, notice that double1 and double2 call function double() , so separate execution context are created for each function call.

execution.jpg

qpYCndgde.jpg

double1 = double(n) is called first so FEC for is created and it is pushed to the top call stack.

Function Execution Context for double(n) is created and the memory creation phase is completed. The argument of the function is also given memory and initialized to special value undefined.

R374Z-r3F (1).jpg

In the execution phase of double(n), the variables and arguments are initialized to their values. Even the values from the Global Execution Context can be accessed here. After the encounter of the return keyword, the FEC is ended and gets pop off the stack. double1 is returned with value 4 resulting in double1=4. The call stack would look like this:

Xjkh5YkSm.png

Now at double2 = double(4) , the double() is again called. Hence a new FEC for this call is created. FEC of this will be pushed at top of the stack. The memory created would occur and in the execution phase And the context and call stack would be like this:

xFo7iAyP2.jpg

Gtmka1SM7.jpg

As soon the double2 = double(4) function context returns the computed value, it is popped off the stack. Now there is no more line to execute in the GEC so it is also popped off the stack and the stack is empty. In the end, the memory component would be similar to:

dyo9t1M9W.jpg

When Javascript completes the execution, then the Global Execution Context is deleted and Call Stack is empty

Wrap up

Execution Context and Call stack are the very important topic for every Javascript developer. Having an idea of how the code works under the hood will sure help in better understanding the code, debugging, and writing cleaner code. A special thanks to Akshay Saini for explaining these things and encouraging me to help others. It was an honest effort to help beginners like me to have in-depth knowledge about the Foundations of Javascript. Thanks for reading!

ย