V8 执行一段JS代码

384 阅读3分钟

首先需要明白的是,机器是读不懂 JS 代码,机器只能理解特定的机器码,那如果要让 JS 的逻辑在机器上运行起来,就必须将 JS 的代码翻译成机器码,然后让机器识别。JS属于解释型语言,对于解释型的语言说,解释器会对源代码做如下分析

  • 通过词法分析和语法分析生成 AST(抽象语法树)
  • 生成字节码

1. 生成 AST

AST即将一行行的代码分解成一个个token

let name = 'sanyuan'

词法分析拆分方式

微信截图_20220329134610.png

解析成了四个token,这就是词法分析的作用。

语法分析阶段,将生成的这些 token 数据,根据一定的语法规则转化为AST

微信截图_20220329135037.png 当生成了 AST 之后,编译器/解释器后续的工作都要依靠 AST 而不是源代码

babel原理

可参考荒山的**babel文章**, babel 的工作原理 将ES5 的代码解析生成ES5的AST, 然后将ES5 的 AST 转换为 ES6 的AST, 最后才将 ES6 的 AST 转化为具体的 ES6 代码 生成 AST 后,接下来会生成执行上下文

2.生成字节码

生成 AST 之后,直接通过 V8 的解释器(也叫Ignition)来生成字节码,字节码最后转换未机器码

  • 为何不直接转换为机器码 早期v8确实是这么操作的,但是机器码占用内存过大,导致严重内存问题
  • 字节码到底是什么 子节码是介于AST 和 机器码之间的一种代码,但是与特定类型的机器码无关,字节码需要通过解释器将其转换为机器码然后执行。
字节码仍然需要转换为机器码,但和原来不同的是,
现在不用一次性将全部的字节码都转换成机器码,而是通过解释器来逐行执行字节码,
省去了生成二进制文件的操作,这样就大大降低了内存的压力。

3.执行代码

在执行字节码的过程中,如果发现某一部分代码重复出现,那么 V8 将它记做热点代码(HotSpot),然后将这么代码编译成机器码保存起来,这个用来编译的工具就是V8的编译器(也叫做TurboFan) , 因此在这样的机制下,代码执行的时间越久,那么执行效率会越来越高,因为有越来越多的字节码被标记为热点代码,遇到它们时直接执行相应的机器码,不用再次将转换为机器码。

其实当你听到有人说 JS 就是一门解释器语言的时候,其实这个说法是有问题的。因为字节码不仅配合了解释器,而且还和编译器打交道,所以 JS 并不是完全的解释型语言。而编译器和解释器的 根本区别在于前者会编译生成二进制文件但后者不会。

并且,这种字节码跟编译器和解释器结合的技术,我们称之为即时编译, 也就是我们经常听到的JIT

4.总结

    1. 首先通过词法分析和语法分析生成 AST
    1. 将 AST 转换为字节码
    1. 由解释器逐行执行字节码,遇到热点代码启动编译器进行编译,生成对应的机器码, 以优化执行效率