JavaScript 调用栈

摘要: 本教程将介绍 JavaScript 调用栈,它是一种用于跟踪函数调用的机制。

JavaScript 调用栈简介

调用栈是 JavaScript 引擎用来跟踪其在调用多个函数的代码中的位置的一种方式。它包含有关当前正在运行的函数以及从该函数中调用的函数的信息……

此外,JavaScript 引擎使用调用栈来管理执行上下文

  • 全局执行上下文
  • 函数执行上下文

调用栈的工作原理基于后进先出 (LIFO) 原则。

执行脚本时,JavaScript 引擎会创建一个全局执行上下文并将其推入调用栈顶部。

每当调用一个函数时,JavaScript 引擎都会为该函数创建一个函数执行上下文,将其推入调用栈顶部,并开始执行该函数。

如果一个函数调用另一个函数,JavaScript 引擎将为被调用的函数创建一个新的函数执行上下文,并将其推入调用栈顶部。

当前函数完成后,JavaScript 引擎会将其从调用栈中弹出并恢复执行之前的状态。

当调用栈为空时,脚本将停止执行。

JavaScript 调用栈示例

让我们从以下示例开始

function add(a, b) {
    return a + b;
}

function average(a, b) {
    return add(a, b) / 2;
}

let x = average(10, 20);
Code language: JavaScript (javascript)

当 JavaScript 引擎执行此脚本时,它会将全局执行上下文 (用main()global()函数表示) 放入调用栈。

JavaScript Call Stack - main

全局执行上下文进入创建阶段,然后进入执行阶段。

JavaScript 引擎执行对average(10, 20)函数的调用,并为average()函数创建一个函数执行上下文,将其推入调用栈顶部。

JavaScript Call Stack - step 2

JavaScript 引擎开始执行average(),因为average()函数位于调用栈顶部。

average()函数调用add()函数。此时,JavaScript 引擎为add()函数创建一个新的函数执行上下文,并将其放置在调用栈顶部。

JavaScript Call Stack - step 3

JavaScript 引擎执行add()函数并将其从调用栈中弹出。

JavaScript Call Stack - step 4

此时,average()函数位于调用栈顶部,JavaScript 引擎执行并将其从调用栈中弹出。

JavaScript Call Stack - step 5

现在,调用栈为空,因此脚本停止执行。

JavaScript Call Stack - empty stack

下图说明了所有步骤中调用栈的总体状态。

JavaScript Call Stack

栈溢出

调用栈的大小是固定的,取决于宿主环境 (Web 浏览器或 Node.js) 的实现。

如果执行上下文的数量超过栈的大小,将会发生栈溢出错误。

例如,执行一个递归函数时,如果它没有退出条件,JavaScript 引擎将发出栈溢出错误。

function fn() {
    fn();
}

fn(); // stack overflowCode language: JavaScript (javascript)

异步 JavaScript

JavaScript 是一种单线程编程语言。这意味着 JavaScript 引擎只有一个调用栈。因此,它一次只能执行一个操作。

执行脚本时,JavaScript 引擎会从上到下、逐行执行代码。换句话说,它是同步的。

异步意味着 JavaScript 引擎可以在等待另一个任务完成时执行其他任务。例如,JavaScript 引擎可以

  • 向远程服务器请求数据。
  • 显示一个加载指示器
  • 当数据可用时,将其显示在网页上。

为此,JavaScript 引擎使用事件循环,这将在下一教程中介绍。

总结

  • JavaScript 引擎使用调用栈来管理执行上下文。
  • 调用栈使用基于 LIFO (后进先出) 原则的栈数据结构。
本教程对您有帮助吗?