],
"sourceType": "module"
1-2. Ignition 阶段
Ignition 阶段:Ignition解释器将 AST 转换为字节码,解析执行字节码也会为下一个阶段优化编译提供需要的信息;
早期的V8版本,将依据JS代码生成的AST直接编译为机器码,是不存在生成字节码这个环节的。但会存在一些问题,机器码比字节码会占据更大的内存空间,会导致内存占用过大,在手机端浏览器内存并没有PC端这么大,也会带来问题。并且,在AST中,函数声明仅仅是一个节点,在函数调用执行时才会进入解析执行,没必要直接将要函数声明也编译生成机器码,占据内存空间,用时编译会更加方便。
字节码是对机器码的抽象描述,相对于机器码,其代码量更小,可减少内存消耗。字节码的语法已经非常接近汇编语言。
所以,AST生成字节码,内存占用明显下降。
1-3. TurboFan 阶段
TurboFan 阶段:TurboFan编译器利用上个阶段收集的信息,将字节码优化为可以执行的机器码;
热点代码(HotSpot):在上一个阶段(Ignition 阶段)中,Ignition 解释器生成的字节码 如果被执行很多次,这段代码会被发送给 TurboFan编译器 ,TurboFan将其编译为机器码,下次执行这段代码时,会执行生成的机器码,提升了代码执行效率。
优化后的机器码类似于缓存。
优化回退:当热点代码不再被频繁执行,或者热点函数的传入数据类型发生变化,TurboFan会将之前生成的机器码删除,执行过程回到Ignition的字节码。
1-4. Orinoco 阶段
Orinoco 阶段:垃圾回收阶段,将程序中不再使用的内存空间进行回收。
2. 浏览器 执行 JS 经历的阶段
V8是浏览器内部JS引擎,算是从微观层面进行剖析。下面从浏览器的宏观层面进行看JS代码的执行过程。
2-1. 语法分析阶段
语法分析阶段:进行语法分析,检查是否有语法错误,有的话则在浏览器控制台抛出异常。
2-2. 编译阶段
编译阶段:进行执行上下文的创建,包括创建变量对象(AO/GO)、建立作用域链、确定 this 的指向等。
上下文的创建依赖于JS运行环境,JS运行环境包括:全局环境、函数环境和eval。
2-2-1. 创建变量对象(AO/GO)
变量对象:每个执行上下文都会通过变量对象存储所需要的变量和函数。
在浏览器中,全局环境的变量对象是window对象,Global Object俗称GO。
在函数环境下,变量对象将会创建arguments对象,同时检查变量声明和函数声明,并且进行初始化。函数被调用时,会形成局部作用域Activation Object俗称AO。
JavaScript 采用的是词法作用域(Lexical Scoping),即静态作用域。词法作用域中的变量,在编译过程中会产生一个确定的作用域。
创建变量的过程会产生作用域,作用域也被称为词法环境,它由两个成员组成:环境记录、外部词法环境引用。
环境记录(Environment Record):用于记录自身词法环境中的变量对象。
外部词法环境引用(Outer Lexical Environment):记录外层词法环境的引用。
2-2-2. 建立作用域链
建立作用域链:将各个作用域通过某种方式链接起来。通过外部词法环境的引用,作用域可以层层拓展,建立起从里到外延伸的一条作用域链。
js预编译AO对象及GO对象
2-2-3. 确定this指向
确定this指向:this指向最后调用当前代码的那个对象。
(1)全局环境:指向全局对象,浏览器中的全局对象是window。 (2)函数内部:类的构造函数,this是常规对象;函数作为对象方法被调用,this指向