JavaScript execution context — call stack and multiple execution contexts (part 2)

In the previous post, we talked about the execution context. It was the first execution context created at the compiling step.

We call this very first execution context, the global execution context (global EC). The variables stored in the corresponding variable environment are global variables.

The global execution context is not along. Multiple execution contexts could be created and removed when running a script.

Where are these execution contexts from?

An execution context is always linked to a compiling step. Multiple execution contexts imply many compiling steps.

This mechanism is associated with functions.

Let’s see an example with a function.

We know the console logs `20` at the end of the execution, but what happened in the execution contexts?

As always, it starts with a compiling step, and it creates a global execution context.

In the variable environment, we see the `apple` and `appleTotal` variables and the `total` function. The compiling ends and the execution starts.

The `apple` variable is updated to `10`, then the JavaScript engine reads the `total()` part.

At this moment, the same two-step process repeats. The compiling step starts again, but this time, it occurs to the `total` function only.

The JavaScript engine creates a new execution context, the `total` execution context, and stacks it on top of the global execution context.

We call this structure a stack.

The stack has a unique feature: last in, first out. That’s the only feature we care about in this mechanism.

Same as the global one, a variable environment exists in the `total` execution context, with an undefined `price` variable.

Next, in the `total` execution context, the execution step starts. The `price` variable is updated to `2`.

Then, the function finds the `price` variable in the `total` execution context and the `apple` variable in the global one.

Nice, it finds both variables, and the computation result is returned.

At the same moment, the returned value is assigned to the `appleTotal` variable in the global execution context.

There are no remaining executable scripts in the `total` execution context, so the JavaScript engine removes it from the stack.

The `total` execution context is the last one getting into the stack, so it is the first one that leaves the stack.

Now we have the last one at the bottom of the stack, the global execution context.

The only remaining executable script is logging the variable `appleTotal` in the console. After doing that, the entire process is completed.

From the example, we can see how the JavaScript engine manages execution contexts.

  • The JavaScript engine does not compile codes in a function until the function is called.
  • When a function is compiled, a new execution context is created and put at the top of the stack.
  • All execution contexts are managed in a stack structure. The process happens from the top of the stack to the bottom.
  • The two-step process, compiling and execution, happens whenever a function is called.

Based on the way the execution contexts stacking at the top of each other, we call it the call stack.

Check your JavaScript call stack in a browser

The modern browsers make it easy to check the call stack in its dev tools. Here is an example of Chrome.

To check the call stack, we need

  1. an HTML file, and
  2. a breakpoint

The following codes are for the HTML file, but you can always come up with your own one.

<script>
var apple = 10;
function total() {
var price = 2;
return apple * price;
}
var appleTotal = total();console.log(appleTotal);
</script>

Run the HTML file in Chrome, and open the “Sources” panel in the dev tools.

On the “Sources” panel, we add a breakpoint in the `total` function.

Next, refresh the page, the call stack shows. The “total” one is the `total` execution context, and the “anonymous” is the global execution context.

What are the takeaways?

  • Multiple execution contexts are managed in a stack structure. It is the JavaScript call stack.
  • JavaScript engine repeats the two-step process, compiling and execution, to add and remove execution contexts.
  • New execution contexts are added to the top, and the top one has the priority to complete first.
  • There is only one global execution context, and it always stays at the bottom of the call stack. It displays as the “anonymous” call stack in a browser dev tools.

Up next…

References

  • It is worth mentioning that the call stack is not a real stack data structure defined in the backend programming world. The browser simulates the stack data structure, so they are not entirely the same.
  • If you are curious about the stack data structure, this reply shares an intriguing analogy.
  • If you are using Firefox, this post can help you check the call stack.
  • The freeCodeCamp team has a great post on the call stack with more code examples.

a coder 👨‍💻