How does a JavaScript Program Execute?

How to execute JavaScript program

Well, we have been learning JavaScript for quite a while now. So, now it is time to know the basics of how the JavaScript program executes. It is pretty easy, and it will also unfold many different concepts for us soon. So, let’s dive in to understand the working of a JavaScript program –

First, remember that whenever we run a JavaScript program, an execution context is created. There are basically 2 types of execution contexts, one being the global execution context(GEC), and the another is the function execution context(FEC). We are going to understand this as well.

How to execute JavaScript program

We are running our JavaScript programs mostly in browsers right now. What we are writing is a human understandable code. But in order for our computer to understand our code, the program must be converted to binary language(0s and 1s). So, who is going to do this for us? Well, here, in the browsers, we have something called a JavaScript engine. Many major browsers that we use today have got some JavaScript Engine, with some different names, like Chrome has V8, Firefox has SpiderMonkey, etc.

This JavaScript engine is the software that is responsible to take our JavaScript programs, and converting them into computer understandable language(binary language).

So, first of all, before any code executes(executing a script for the first time), the Global Execution Context is created. Also, whenever some function is executed, a new function execution context is created. This is pretty amazing, and we are going to slowly dive into it.

Well, this global execution context is only created once. But wait… what does this execution context thing contain in general? Let’s now discuss this as well.

In very general terms, the execution context contains some information about the currently running code.

Let’s have a look at a simple example so that it becomes easy for us to understand what is this execution context.

As you can see in the above program, we have created one variable, with the name of some variable. After that, we have a function someFunction, in which, there is some code basically.

Then we are also calling the function someFunction. This is what we know. But now, we are more interested in going behind the scenes.

So, basically, there are two phases for the execution context to be created. The first phase is the creation phase, and the next phase is the execution phase.

In the creation phase, we are going to store some important information that is going to be used by the code in the runtime.

This includes the variables and the functions that we have in our JavaScript programs. So, basically, in the creation phase, we are also creating a variable object (or variable environment), in which, we are going to have variable and function declarations that are defined within that execution context. So, let’s first create a dummy execution context(which is going to be a global execution context here), and let’s understand what is there in the execution context.

Variable Environment Code Environment
SomeVariable: undefined
SomeFunction: {
var anotherVariable = 20;
console.log(“Hello, from GyaniPandit!”);
console.log(“The value in another variable: “+ anotherVariable);
}

As you can see, in the creation phase, the memory is allocated to the variables and the functions that are defined in that particular execution context. Notice that at first, the same variable is containing the value undefined(since it is created using the var keyword, otherwise there would have been some different story).

Also, notice that for the function, we are literally storing the whole block of code of that function. Also, one more thing to notice, is that we are having these things as the key:value pairs, which means that there is going to be a key, and an associated value with it.

Remember that in the creation phase, the JavaScript engine went through the code and created the Variable object. Now, there is the next phase as well, which is the execution phase. Now, after the memory allocation, we are now going to execute the program. So, once again, the Engine is going to go through our program and executes it line by line. So, when it comes to the first line to execute, it is placing the value 10 with the same variable. After that, we have the function declaration, so it is not going inside that, because we have not called the function yet(when we will call the function, a new FEC will be generated).

After that, we are calling the function, so, a new Function execution context is generated. This is also going to have some similar things to what we saw in the execution context, but there are certain points of difference as well.

Again, the creation of this execution context proceeds in a similar way. So, let’s create the execution context for the function –

Variable Environment Code Environment
some variables: 10 Variable Environment Code Environment
someFunction: {
var another variable = 20;
console.log(“Hello, from GyaniPandit!”);
console.log(“The value in another variable: “+ another variable);
}
anotherVariable: undefined

Now, as you can see, since we are now executing the program, the someVariable holds a value of 10 now. Also, we have called the function. So, a new Function Execution context gets generated. As you can see, the other variable is now completely in a new environment.

When the function is going to be executed line by line, the other variable will be given the value that it is supposed to hold, which is 20. Also, if the function is supposed to have some argument, then accordingly the value will be stored in that context.

So, after the function has finished execution, the function execution context is deleted, and after the whole program is done with execution, the Global Execution Context is deleted as well.

Also, there is something called a call stack. The call stack is something that is used by JavaScript to keep account of multiple function calls. Just like a real stack(from the data structures), we are pushing data to and popping data from the stack. We can say that the with a call stack, we can also monitor the order of execution of the functions, like which function is currently executing, or what order are the functions called for example.

So, when a function is called, it is added to the call stack, and then the execution is started. Also, when the current function has finished execution, it is removed from the call stack, and the execution is resumed from where it had left off.

Remember that, if the call stack takes more space than assigned, then it results in a stack overflow error.

So, let’s now have a look at a simple program, to understand the working of the call stack.

As you can see, first of all, we have created a variable, with the name of some variable. Then, we have created two functions, the someFunction, and the anotherFunction. Also, we can see that we are calling another function, inside the same function, and at last, we are calling the same function.

So, it goes something like this –

first of all, the GEC will be generated. Then we are calling the function someFunction here. So, the entry for the someFunction is made into the call stack, and the function executes then. It appears something like this if we try to visualize it in the browser –

We are using the browser dev tools, to debug the JavaScript program. I have put breakpoints at different locations here. As you can see, currently, we are executing the function someFunction, and the same thing, you can see in the call stack as well.

Now, let’s execute one more step, and have a look at the changes in the call stack –

As you can see, in the call stack, the anotherFunction is now on the top of the someFunction. This has to tell that right now, we are executing anotherFunction, which was called from the someFunction. Now, when another anotherFunction will finish execution, it will be popped off from the stack.

In the end, when all the functions are done with execution, the call stack is empty. So, this was some basics about the call stack, and the execution context as well.