js底层精讲:代码到底如何运行1

103 阅读4分钟

本文旨在让你对JavaScript代码运行的底层原理有个大致的认识(有些地方不会展开讲),细枝末节会在后续的章节慢慢梳理,掌握了框架对后续的学习是非常有指导意义的。

JavaScript引擎

JavaScript引擎是执行JavaScript代码的程序。常见的JavaScript引擎包括Google的V8(用于Chrome和Node.js)、Mozilla的SpiderMonkey(用于Firefox)和Apple的JavaScriptCore(用于Safari)。引擎负责解析、编译和执行JavaScript代码。 那么我们都知道计算机只认0和1。一段代码想要被执行,是必须要把高级语言转换成低级语言(能间接控制硬件行为),使其能被机器识别后才会执行的。但其实说白了,转换的过程用的也是一段程序,而这段程序我们喜欢把它叫作引擎

大部分JS引擎采用JIT技术

JIT(Just-In-Time即时编译) 是一种编程语言执行方式,它在程序运行时将代码编译为机器代码,而不是在程序启动时提前编译(如传统的编译方式)或逐行解释(如解释型语言)。JIT编译器结合了编译和解释的优点,可以提高代码的执行效率,尤其是在动态语言(如JavaScript、Java等)中表现得尤为明显。

以v8引擎(由Google开发,没错就叫v8)展开讲,v8引擎是一个接收JavaScript代码,编译代码然后执行的c++程序,编译后的代码可以在多种操作系统、多种处理器上运行。 V8引擎要负责以下工作:JS代码的编译和执行、处理调用栈(这个会重点讲)、内存的分配和垃圾的回收。

它把代码的运行和生成可执行的代码这两个过程结合在了一起,在运行阶段收集信息,然后根据这些信息生成机器码,最后再执行机器码(这个过程一般会被重复多次)。

af7cf24738682ad24af8deca26ee06e.png

JS代码的执行步骤(先作了解)

从源代码到最终执行,主要包括以下阶段:

1. 词法分析(Lexical Analysis)

将源代码文本分解成一个个标记(tokens)。

let sum = 1 + 2;

// 词法分析后的标记
[
    { type: 'keyword', value: 'let' },
    { type: 'identifier', value: 'sum' },
    { type: 'operator', value: '=' },
    { type: 'number', value: '1' },
    { type: 'operator', value: '+' },
    { type: 'number', value: '2' },
    { type: 'punctuator', value: ';' }
]

2. 语法分析(Syntax Analysis/Parsing)

将标记转换为抽象语法树(AST)。

3. 预编译阶段

在代码执行之前的准备工作。

  • 创建执行上下文

  • 变量提升(这个特性并不好)

// 原代码
console.log(a);
var a = 2;

// 预编译后的实际执行顺序
var a;
console.log(a); // undefined
a = 2;

4. 字节码生成

将AST转换为字节码(以V8引擎为例)。

// 伪字节码示例
LdaConstant [0]    // 加载常量1
Add a1             // 加法操作
Star r0           // 存储结果

5. 执行阶段

代码实际运行的阶段。

  • 解释执行

  • JIT编译

6. 运行时优化

  • 内联缓存(Inline Caching)

  • 类型反馈(Type Feedback)

记录参数类型信息以优化后续调用

7.垃圾回收

JavaScript引擎还负责管理内存,自动清理不再使用的内存空间。垃圾回收机制会周期性地执行,以避免内存泄漏和其他内存相关的问题。

8. 事件循环(Event Loop)

负责处理异步操作和事件。事件循环的主要任务是监控调用栈和任务队列,并将任务从队列中移动到调用栈中执行。

9. 错误处理

示例

function calculateSum(a, b) {
    let result = a + b;
    return result;
}

let x = 10;
let y = 20;
console.log(calculateSum(x, y));

//   执行过程
// - 词法分析:分解为tokens
// - 语法分析:生成AST
// - 预编译:创建执行上下文,处理变量提升
// - 生成字节码
// - 执行:
//   * 创建函数对象
//   * 分配变量内存
//   * 执行函数调用
//   * 进行必要的优化
// - 可能的运行时优化

结语

如果看的有点累,这完全没关系。你只需要清楚js代码运行时大概有这么些任务,并且这些任务依赖于引擎,具体如何完成任务我会在后续的章节一 一(yi yi)介绍。