js引擎

234 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第6天,点击查看活动详情

浏览器内核的组成

浏览器内核是有两部分组成:

  1. WebCore(渲染引擎): 负责HTML解析、布局、渲染等等相关的工作
  2. JavaScriptCore(JS引擎): 解析、执行JavaScript代码。

js引擎

JS引擎中最典型的就是V8引擎,以下关于JS引擎的机制我都会以V8来介绍

V8是用c++编写的Google开源高性能JavaScript和WebAssembly引擎,它用于Chrome和Node.js等。它实现ECMAScript和WebAssembly,并在window7或更高版本,macOS 10.12+和使用x64,IA-32, ARM或MIPS处理器的Linux系统上运行。V8可以独立运行,也可以嵌入到任何C++应用程序中。

1. V8引擎的执行原理

众所周知,计算机是不认识我们写的JavaScript源码的,它只认识机器语言,也就是0和1。因此特别需要一种工具能够将JavaScript源码转成cpu可以识别的机器语言,这时候JS引擎就开始工作了,下面介绍一下JS引擎是如何将JavaScript源码转成CPU能识别的机器语言的。

image.png

parse解析器: parse模块会将JavaScript代码转成AST树

  • 如果函数没有被调用,那么是不会被转换成AST的

1.1 Igition解释器

会将AST转换成ByteCode(字节码)

  • 同时会收集TurboFan优化所需要的信息(比如函数参数的类型信息,有了类型才能进行真实的运算)
  • 如果函数只调用一次,Ignition会解释执行ByteCode

1.2 TurboFan编译器

可以将字节码编译为CPU可以直接执行的机器码。

  • 如果一个函数被多次调用,那么就会被标记为热点函数,那么就会经过TurboFan转换成优化的机器码,提高代码的执行性能。
  • 但是,机器码实际上也会被还原成ByteCode,这是因为如果后续执行函数的过程中,类型发生了变化(比如sum函数原来执行的是number类型,后来执行变成了string类型)。之前优化的机器码并不能正确的处理运算,就会逆向地转成字节码

1.3 相关问题说明:

问题1: 不把JavaScript源码直接转成CPU能识别的机器语言,而是转成ByteCode?

:在回答这个问题之前,我们先来看看字节码和机器码的区别

  • 机器码,也叫机器语言指令,是计算机可以直接执行,并且执行速度最快的代码
  • 字节码是一种包含执行程序、由一系列op代码、数据对组成的二进制文件。它是一种中间码,需要直译器转译后才能成为机器码的中间代码。

因为JavaScript运行在什么环境是不确定的,它可以运行在windows,macos, linux环境的浏览器中,也可以运行在node环境中。不同环境的CPU是不一样的,对应的机器指令也不一样。转化成字节码的好处就是不管在什么环境中,都可以执行,生成对应的cpu机器指令。

问题2: 上面的流程图里面已经有一个流程是可以转成字节码的(JavaScript源代码 --> parse --> AST抽象语法树 --> Ignition --> bytecode字节码 --> 运行结果),为什么还会有下面的流程呢?

: 假如有个函数被重复调用了,如果只有这一个流程的话,它就会每次都需要从头开始去执行这个流程,这样的话是会非常降低性能的。如果可以将函数转成机器指令并且保存下来,然后需要调用这个函数的时候,就直接执行机器指令。这种方式适合多次调用函数,如果只调用一次函数,那么就没有必要转成机器指令然后保存起来。

2. V8引擎的解析原理

V8引擎的解析过程其实就是将JavaScript源码转成AST树。具体解析如图所示:

image.png

2.1 主要流程

  1. Blink将源码交给V8引擎,Stream获取到源码并且进行编码转换
  2. scanner会进行词法分析,词法分析之后会将代码转换为成词法单元(tokens)。如:var a = 2;。这段程序通常会被分解成为下面这些词法单元:var、a、=、2 、;。
  3. tokens会被转换为AST树,经过Parser和PreParser:Parser直接将tokens转成AST树架构,PreParser是预解析。var a = 2;的抽象语法树中可能会有一个叫作VariableDeclaration的顶级节点,接下来是一个叫作Identifier(它的值是a)的子节点,以及一个叫作AssignmentExpression的子节点。AssignmentExpression节点有一个叫作NumericLiteral(它的值是2)的子节点。
  4. 后面的流程就是上面的代码执行流程

2.2 相关概念

词法分析(lexical analysis): 将字符序列转成token序列的过程

  • token是记号化(tokenization)的缩写
  • 词法分析器(lexical analyzer, 简称lexer), 也叫扫描器(scanner)

语法分析(syntactic analysis, 也叫parsing)

  • 语法分析器也可以称之为parser.