Skip to content

JavaScript Advanced (III)—Execution Context Stack

About 559 wordsAbout 2 min

javascript

2020-02-11

For the execution context, please click this article.

Execution context stack

The JavaScript engine creates an execution context stack to store and manage all execution contexts created when code is executed.

Execution context stack (ECS) is a stack with LIFO (latest in first out).

We use an array to simulate the execution context stack:

const ECSStack = []

When JavaScript is executed, the first thing we encounter is global code. When initialized, the global execution context will be first pushed into the execution context stack. (global execution context). It will only be cleared when the entire program ends, so before the program ends, the bottom of ECSStack There will be a globalExecutionContext

const ECSStack = [globalExecutionContext]

When JavaScript starts executing the following code:

function foo() {
  console.log('foo')
}
function bar() {
  foo()
}
function run() {
  bar()
}

run()

In this code, JavaScript performs the following processing:

// pseudocode:

// run(), create the function execution context and push the execution context stack
ECSStack.push(functionExecutionContext<run>)

// I found that bar() needs to be executed in run(), continue to create the function execution context and push it into the execution context stack
ECSStack.push(functionExecutionContext<bar>)

// I found that foo() needs to be executed in bar(), continue to create the function execution context and push it into the execution context stack
ECSStack.push(functionExecutionContext<foo>)

/** At this time, the structure of ECSStack is as follows:
 * [
 * globalExecutionContext,
 * functionExecutionContext<run>,
 * functionExecutionContext<bar>,
 * functionExecutionContext<foo>
 * ]
 */

// When foo() is executed, remove functionExecutionContext<foo> from the execution context stack
ECSStack.pop()

// When bar() is executed, remove functionExecutionContext from the execution context stack<bar>
ECSStack.pop()

// When run() is executed, remove functionExecutionContext<run> from the execution context stack
ECSStack.pop()

// There is always a globalExecutionContext at the bottom of the ECSStack when the program is not finished

Let's take a look at the next example:

var scope = 'global scope'
function checkScope() {
 var scope = 'local scope'
 function f() {
 Return scope
 }
 return f()
}
checkScope()
var scope = 'global scope'
function checkScope() {
 var scope = 'local scope'
 function f() {
 Return scope
 }
 Return f
}
checkScope()()()

Although the execution result of these two pieces of code is the same, they both output local scope, but the changes in the execution context stack are different.

The first piece of code, on the execution context stack, simulated processing is as follows:

// Execute checkScope()
ECSStack.push(functionExecutionContext<checkScope>)
// Execute f() in checkScope execution phase
ECSStack.push(functionExecutionContext<f>)

ECSStack.pop()
ECSStack.pop()

The second piece of code, in the execution context stack, simulated processing is as follows:

// Execute checkScope()
ECSStack.push(functionExecutionContext<checkScope>)
ECSStack.pop()
// After checkScope is completed, execute f()
ECSStack.push(functionExecutionContext<f>)
ECSStack.pop()

It can be seen that the timing of function execution is different. Although the final results are consistent, the processes in the execution context stack are different.

Summarize

  1. The execution context stack is used to store and manage all execution contexts.
  2. Before the program ends, there is always a global execution context in the execution stack.
  3. When a function is executed, a new function execution context is created and pushed into the execution stack in order.
  4. After the function execution is completed, the corresponding function execution context will be removed from the execution stack.