JavaScript Interview Preparation Cheat-Sheet:  Execution context, call stack, creation phase

JavaScript Interview Preparation Cheat-Sheet: Execution context, call stack, creation phase

Have you ever wondered what happens internally when you execute your JavaScript code on a browser console or node.js environment? Let's find it out.

By the end of this article, you will have enough idea of topics like execution context, call stack, variable environment, the thread of execution etc.

This environment is known as JS runtime. In most cases, that environment would be a web browser or node.js. It is like a container that contains a JS engine, Web APIs, callback queues etc. to run JS code in a synchronous single-threaded manner. Do not get overwhelmed by all this jargon, let me demystify all of them for you.

When the browser parses through HTML, if it encounters JavaScript code, it will send it to its JavaScript engine to execute. Since the browser doesn't understand the high-level JS code, so JS engine first transforms the code into machine code and then executes it.

Every browser has its own JS engine. For example, Google has V-8 engine which powers google chrome.

Transformation of JS code into machine code

This includes tokenizing, parsing, and then just-in-time compilation of JS code. For the sake of making this article focus on the things that happen under the hood while executing JS code, I am covering this step of the transformation of JS code into machine code in this article. Just remember, we have now machine code that we are going to execute. Still, following me? Great, let's move ahead...

Execution of JS code

Once JS code is compiled, it is ready to be executed. All JavaScript code needs to be executed in some kind of environment. JS engine provides this environment & it is known as execution context(EC). It stores all the information of the piece of code required to execute it such as variable environment, scope chain, closure, and this keyword.

How is the execution context created?

Since Global EC is the first one to be executed, Let's break it down its creation. The JavaScript code goes through two steps when we execute it:-

  1. Creation phase/Memory allocation phase

  2. Execution phase/ thread of execution

Creation phase/Memory allocation phase

In this phase, the JS engine begins its compilation phase and scans the particular function code for compiling it but does not execute the code.

in other words, the JS engine will read/scan the JS code line by line and perform the following tasks.

  1. creation of a variable environment/memory component

While scanning the code, the JS engine stores the variables and functions here in a key-value format. How it is all done, let us understand using an example.

var x = 7;
let y = 7;  // ES6 feature
const z = 7;

// function declaration
function act(){
    console.log("krishna");
}

// function expression 
var act1 = function(){
    console.log("krishna");
}

// arrow function - ES6 feature
cosnt act2 = () => console.log("krishna");

Now, first JS engine will scan the code line by line.

It will encounter a variable declared with var keyword. During this creation phase, JS engine will store it in a memory space with a special value undefined. Don't ask why, this is how JS works with var.

In the case of variables declared with let and const , the JS engine stores in separate memory space but hey remains uninitialized. It means, JS is aware of their existence, but we cannot access them before their declaration unlike variables declared with var. This concept is known as Hoisting and is covered in depth here in this article.

Function declarations are stored with the value of all the code written in its scope/block.

Function expression and arrow functions act like variables and their value become undefined or they become uninitialized depending upon how they are declared.

  1. creation of scope & scope chain

    Even before the execution of the very first line, the JS engine is aware of all the variables and functions defined in the program which are stored in their respective memory space. We will talk about this memory space(also known as scope) in detail in this article.

    This will include scope, scope chain, lexical environment and this keyword.

Execution Phase

After completion of the creation phase, the JS engine will scan the code again and execute the code line by line. It will update the actual value of the variables.

Types of Execution context

There are two types of execution context in JS-

  1. Global EC

  2. Function EC

Global Execution context

As soon as the JS engine receives a JS code file, it creates a global execution context for all the top-level code(the piece of code that is not inside any block/function scope). This piece of code executes when the file first loads/executes in the browser. Hence known as global EC.

No matter how large is our JS code, there is exactly one global EC. It will be created even for an empty JS file.

Function execution context

JS engine creates an EC for every function call inside the JS code. It can be more than one. The function EC has access to the code of global EC but vice-versa is not possible. When the JS engine encounters any function definition (be it function declaration, function expression, or arrow function), the JS engine will create the execution context for this function. This step will involve all the tasks of the creation phase and the execution context for this function.

Call Stack

A call stack is a way for the JavaScript engine to keep track of its place in code that calls multiple functions. It has the information on what function is currently being run and what functions are invoked from within that function

Javascript is a single-threaded language, which means the Javascript engine executes JS code line by line. When you execute a script, the JavaScript engine creates a global execution context & pushes it inside the call stack, and starts executing it.

During the execution of the global execution context, if the JS engine encounters any function invoking code, then the execution context of that function will be pushed on top of the global execution context and now the JS engine will start executing this function execution context immediately.

If during the execution of this function, the JS engine encounters any other function invoking code, then the execution context of that new function will be pushed on top of the current function execution context and now the JS engine will start executing this function execution context immediately.

Now further, if the JS engine does not find any other function invoking code in this function, it will execute it and this latest execution context will be popped off from the call stack. The control will now go in top most execution context and will start executing it.

Call stacks follows FIFO

This is how the call stack executes the main thread and ensures concurrency in Javascript.

At the end, the global execution context remains in the call stack which remains there unless the tab is closed.

That's it, folks! That's all about Execution context and Call stack.

if you want to know, how JS handles asynchronous operations, here is your complete guide.

Follow me for more in-depth articles. Leave your feedback in the comment section.