本文旨在让你对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代码的编译和执行、处理调用栈(这个会重点讲)、内存的分配和垃圾的回收。
它把代码的运行和生成可执行的代码这两个过程结合在了一起,在运行阶段收集信息,然后根据这些信息生成机器码,最后再执行机器码(这个过程一般会被重复多次)。
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)介绍。