文章目录
1. 深入V8引擎原理
1.1 JavaScript代码的执行
JavaScript代码下载好之后,是如何一步步被执行的呢?
我们知道,浏览器内核是由两部分组成的,以webkit为例:
另外一个强大的JavaScript引擎就是V8引擎。
1.2 V8引擎的执行原理
我们来看一下官方对V8引擎的定义:
- V8是用C++编写的Google开源高性能JavaScript和WebAssembly引擎,它用于Chrome和Node.js等。
- 它实现ECMAScript和WebAssembly,并在Windows 7或更高版本,macOS 10.12+和使用x64,IA-32,ARM或MIPS处理
器的Linux系统上运行。 - V8可以独立运行,也可以嵌入到任何C ++应用程序中。
接下来会对这幅图进行解析
1.3 V8引擎的架构
V8引擎本身的源码非常复杂,大概有超过100w行C++代码,通过了解它的架构,我们可以知道它是如何对JavaScript执行的:
- Parse模块会将JavaScript代码转换成AST(抽象语法树),这是因为解释器并不直接认识JavaScript代码;
- 如果函数没有被调用,那么是不会被转换成AST的;
- Parse的V8官方文档:https://v8.dev/blog/scanner
- Ignition是一个解释器,会将AST转换成ByteCode(字节码)
- 同时会收集TurboFan优化所需要的信息(比如函数参数的类型信息,有了类型才能进行真实的运算);
- 如果函数只调用一次,Ignition会解释执行ByteCode;
- Ignition的V8官方文档:https://v8.dev/blog/ignition-interpreter
- TurboFan是一个编译器,可以将字节码编译为CPU可以直接执行的机器码;
- 如果一个函数被多次调用,那么就会被标记为热点函数,那么就会经过TurboFan转换成优化的机器码,提高代码的执行性能;
- 但是,机器码实际上也会被还原为ByteCode,这是因为如果后续执行函数的过程中,类型发生了变化(比如sum函数原来执
行的是number类型,后来执行变成了string类型),之前优化的机器码并不能正确的处理运算,就会逆向的转换成字节码; - TurboFan的V8官方文档:https://v8.dev/blog/turbofan-jit
- V8引擎有四个重要模块, 除了以上三个模块外还有第四个模块垃圾回收器, 后续会重点讲到
1.4 V8引擎的解析图(官方)
词法分析(英文lexical analysis)
- 将字符序列转换成token序列的过程。
- token是记号化(tokenization)的缩写
- 词法分析器(lexical analyzer,简称lexer),也叫扫描器(scanner)
语法分析(英语:syntactic analysis,也叫 parsing)
- 语法分析器也可以称之为parser。
2.深入JS代码执行原理
2.1 版本说明
在ECMA早期的版本中(ECMAScript3),代码的执行流程的术语和ECMAScript5以及之后的术语会有所区别:
- 目前网上大多数流行的说法都是基于ECMAScript3版本的解析,并且在面试时问到的大多数都是ECMAScript3的版本内容。
- 但是ECMAScript3终将过去, ECMAScript5必然会成为主流,所以最好也理解ECMAScript5甚至包括ECMAScript6以及更
好版本的内容; - 事实上在TC39(可以看成ECMA的未来版本)的最新描述中,和ECMAScript5之后的版本又出现了一定的差异;
那么我们按照如下顺序学习:
- 通过ECMAScript3中的概念学习JavaScript执行原理、作用域、作用域链、闭包等概念;
- 通过ECMAScript5中的概念学习块级作用域、let、const等概念;
事实上,它们只是在对某些概念上的描述不太一样,在整体思路上都是一致的。
2.2 全局代码执行过程
2.2.1 初始化全局对象
js引擎会在执行代码之前,会在堆内存中创建一个全局对象(在浏览器中也就是window):Global Object(GO)
- 该对象**所有的作用域(scope)**都可以访问;
- 里面会包含Date、Array、String、Number、setTimeout、setInterval等等;
- 其中还有一个window属性指向自己;
2.2.2 执行上下文
js引擎内部有一个执行上下文栈(栈内存)(Execution Context Stack,简称ECS),它是用于执行代码的调用栈。
那么现在它要执行谁呢?执行的是全局的代码块:
- 全局的代码块为了执行会构建一个全局执行上下文(Global Execution Context 简称GEC);
- GEC会被放入到ECS中执行;
GEC被放入到ECS中里面包含两部分内容:
- 第一部分:在代码执行前,在parser转成AST的过程中,会将全局定义的变量、函数等加入到Global Object中,但是并不会
赋值;- 这个过程也称之为变量的作用域提升(hoisting)
- 第二部分:在代码执行中,对变量赋值,或者执行其他的函数;
2.2.3 认识VO对象
每一个执行上下文会关联一个VO(Variable Object,变量对象),变量和函数声明会被添加到这个VO对象中。
- 如果是一个函数, 函数的参数也会添加到VO对象中
当全局代码被执行的时候,VO就是GO对象了
- 全局执行上下文使用全局对象(GO)来作为VO
- 全局执行上下文中的this指向GO(window)
2.2.4 执行过程
示例代码
假如我们有下面一段代码,它在JavaScript中是如何被执行的呢?
var message = "Global Message";
function foo() {
var message = "Foo Message";
console.log(message);
}
var num1 = 10;
var num2 = 20;
var result = num1 + num2;
console.log(result);
foo();
全局代码执行过程(执行前)
- 会定义变量, 但不会赋值
全局代码执行过程(执行后)
- 将变量进行赋值
2.3 函数代码执行过程
在执行的过程中执行到一个函数时,就会根据函数体创建一个函数执行上下文(Functional Execution Context,简称FEC),并且压入到EC Stack中。
因为每个执行上下文都会关联一个VO,那么函数执行上下文关联的VO是什么呢?
- 当进入一个函数执行上下文时,会创建一个AO对象(Activation Object);
- 这个AO对象会使用arguments作为初始化,并且初始值是传入的参数;
- 这个AO对象会作为执行上下文的VO来存放变量的初始化;
示例代码
var message = "Global Message";
function foo(num) {
var message = "Foo Message";
var age = 18;
var height = 1.88
console.log(message);
}
var num1 = 10;
var num2 = 20;
var result = num1 + num2;
console.log(result);
foo(123);
执行过程
3.作用域和作用域链
当进入到一个执行上下文时,执行上下文也会关联一个作用域链(Scope Chain)
-
作用域链是一个对象列表,用于变量标识符的求值;
-
当进入一个执行上下文时,这个作用域链被创建,并且根据代码类型,添加一系列的对象;
-
函数作用域链, 在函数创建的那一刻起, 就已经确定了作用域链
-
作用域链中会保存上层作用域的VO对象, 如果有多层嵌套, 作用域链会保存到全局上下文中VO对应的GO
var message = "Global Message"; function foo() { console.log(message); // Global Message } var obj = { name: "obj", bar: function () { var message = "Bar Message"; foo(); }, }; obj.bar();
-
函数的作用域链与他调用的位置无关, 是在他创建的那一刻, 由他创建的位置决定了的, 例如上述代码中, 函数创建的位置的上层作用域就是全局, 因为foo函数的作用域链就会保存上一层作用域的VO, 因此作用域链保存的是GO
-
在全局上下文还没有执行, 解析的时候, 就创建了foo函数, foo函数有自己VO对应的AO, 当查找message变量时, 会先在自己的AO中查找, 如果查找不到, 就会去作用域链中查找, 作用域链中保存的是全局上下文的VO对应的GO, 因此就会去GO中查找
例如上述代码中, 函数创建的位置的上层作用域就是全局, 因为foo函数的作用域链就会保存上一层作用域的VO, 因此作用域链保存的是GO -
在全局上下文还没有执行, 解析的时候, 就创建了foo函数, foo函数有自己VO对应的AO, 当查找message变量时, 会先在自己的AO中查找, 如果查找不到, 就会去作用域链中查找, 作用域链中保存的是全局上下文的VO对应的GO, 因此就会去GO中查找
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/120143.html