JavaScript高级 执行原理
一、深入V8引擎执行原理
V8引擎架构
Parse模块
Parse模块会将JavaScript代码转为AST
(抽象语法树),这是因为解析器并不直接认识JavaScript代码。
- 如果函数没有被调用,那么是不会被转换成AST的
Ignition模块
Ignition是一个解释器,会将AST转换成ByteCode(字节码)。
- 同时会收集TurboFan优化所需要的信息(比如函数参数的类型信息,有了类型才能进行真实的运算)
- 如果函数只调用一次,Ignition会解释执行ByteCode
TurboFan模块
TurboFan是一个编译器,可以将字节码编译为CPU可以直接执行的机器码。
- 如果一个函数被多次调用,那么它会被标记为热点函数,就会经过TurboFan转换成优化的机器码,提高代码的执行性能
- 但是,机器码实际上也会被还原为ByteCode,这是因为如果后续执行函数的过程中,类型发生了变化(比如sum函数原来执行的是number类型,后来执行变成了string类型),之前优化的机器码并不能正确的处理运算,就会逆向的转换成字节码
V8引擎解析图
二、js执行上下文
js引擎在执行代码前,会在堆内存中创建一个全局对象:Global Object(GO,在浏览器中就是window)。
- 该对象所有的作用域都可以访问
- 里面包含Date, Array, String, Number, setTimeout, setInterval等等
- 其中还有一个window属性指向自己
JS引擎内部有一个执行上下文栈(Execution Contexts Stack, 简称ECS),它是用于执行代码的调用栈。
- 全局的代码块为了执行会创建一个Global Execution Context (GEC)
- GEC会被放到ECS中执行
三、全局代码的执行过程
GEC被放入ECS中包含两部分内容。
- 第一部分:在代码执行前,在parser转成AST的过程中,会将全局定义的变量,函数等加入到Global Object中,但是不会赋值(这个过程也称之为变量的作用域提升)
- 第二部分:在代码执行中,对变量赋值,或执行其他的函数
每一个执行上下文会关联一个VO(Variable Object,变量对象),变量和函数声明会被添加到这个VO对象中。
当全局代码被执行时,VO就是GO。
四、函数代码的执行过程
在执行的过程中执行到一个函数时,就会根据函数体创建一个函数执行上下文(Function Execution Context, 简称FEC),并且压入到ECS中。
因为每个执行上下文都会关联一个VO,那么函数执行上下文关联的VO是什么呢?
- 当进入一个函数执行上下文时,会创建一个AO对象(Activation Object)
- 这个AO对象会使用arguments作为初始化,并且初始值是传入的参数
- 这个AO对象会作为执行上下文的VO来存放变量的初始值
五、作用域和作用域链
当进入到一个执行上下文时,执行上下文也会关联一个作用域链。
- 作用域链是一个对象列表,用于变量标识符的求值
- 当进入一个执行上下文时,这个作用域链被创建,并且根据代码类型,添加一系列的对象
- 原文作者:Gmi_61
- 原文链接:https://www.huangzhishou.com/post/JavaScript%E9%AB%98%E7%BA%A7-%E6%89%A7%E8%A1%8C%E5%8E%9F%E7%90%86.html
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。