JavaScript基础系列开篇:V8是如何运行JavaScript(let a = 1)代码的?

2,446 阅读5分钟

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

你就说吧,有没有资格,有没有资格,有没有资格,肯定有资格的。哈哈。因为我大致了解清楚了,也大致搞明白了一点了。

我们知道,机器是不能直接理解我们平常工作或者自己学习的代码的。所以,在执行程序之前,需要将代码翻译成机器能读懂的机器语言。按语言的执行流程,可以把计算机语言划分为编译型语言和解释型语言:

编译型语言:在代码运行前编译器直接将对应的代码转换成机器码,运行时不需要再重新翻译,直接可以使用编译后的结果。

解释型语言:需要将代码转换成机器码,和编译型语言的区别在于运行时需要转换。解释型语言的执行速度要慢于编译型语言,因为解释型语言每次执行都需要把源码转换一次才能执行。

Java 和 C++ 等语言都是编译型语言,而 JavaScript 是解释性语言,它整体的执行速度会略慢于编译型的语言。V8 是众多JavaScript引擎中性能表现最好的一个,并且它是 Chrome 的内核,Node.js 也是基于 V8 引擎研发的。

1.运行的整体过程

未命名文件 (4).png

2.英译汉翻译的过程

比如我们看到了google V8官网的一篇英文文章 v8.dev/blog/faster…,在阅读的过程中,可以就是要对每一个单词进行解析翻译成中文,然后多个单词进行语法的解析,再通过对整句话进行整个语句进行解析,那么这句话就翻译结束了。

下面我们就举例一句英文的翻译过程:I am a programmer。

  • 1、首先对输入的字符串I am a programmer。进行拆分便会拆分成 I am a programmer

相当于词法分析

  • 2、I 是一个主语, am 是一个谓语, a是一个形容词, programmer是个名词, 标点符号。

  • 3、I的意思, am的意思, a一个的意思, programmer程序员的意思, 句号的意思。

2和3一起相当于语法分析

  • 4、对3中的语法分析进行拼接处理:我是一个程序员。当然这是非常简单的一个英译汉,一篇文章的话,就会复杂一些了。

相当于语义分析

3.V8运行的整个过程

3.1.准备一段JavaScript源代码

let a = 10

3.2.词法分析:

一段源代码,就是一段字符串。编译器识别源代码的第一步就是要进行分词,将源代码拆解成一个个的token。所谓的token,就是不可再分的单个字符或者字符串。

3.3.token

通过 esprima.org/demo/parse.… 可以查看生成的tokens,也就是上面那段源代码生成的所有token。

Token类别: 关键字、标识符、字面量、操作符、数据类型(String、Numeric)等

image.png

3.4.语法分析

将上一步生成的 token 数据,根据语法规则转为 AST。通过astexplorer.net 可以查看生成AST抽象语法树。

3.5.AST

生成的AST如下图所示,生成过程就是先分词(词法分析),再解析(语法分析)

image.png 当然你也可以查看生成的AST的JSON结构

{
  "type": "Program",
  "start": 0,
  "end": 9,
  "body": [
    {
      "type": "VariableDeclaration",
      "start": 0,
      "end": 9,
      "declarations": [
        {
          "type": "VariableDeclarator",
          "start": 4,
          "end": 9,
          "id": {
            "type": "Identifier",
            "start": 4,
            "end": 5,
            "name": "a"
          },
          "init": {
            "type": "Literal",
            "start": 8,
            "end": 9,
            "value": 1,
            "raw": "1"
          }
        }
      ],
      "kind": "let"
    }
  ],
  "sourceType": "module"
}

同样我在本地下载了v8,直接用v8来查看AST

v8-debug  --print-ast hello.js

image.png

3.6.解释器

解释器会将AST生成字节码,生成字节码的过程也就是对AST抽象语法树进行遍历循环,并进行语义分析

3.7.字节码

在最开始的V8引擎中是没有字节码,是直接将AST转换生成为机器码。这种架构存在的问题就是内存消耗特别大,尤其是在移动设备上,编译出来的机器码占了整个chorme浏览器的三分之一,这样为代码运行时留下的内存就更小了。 于是后来在V8中加入了Ignition 解释器,引入字节码,主要就是为了减少内存消耗。 本地可以使用V8命令行查看生成的字节码

v8-debug  --print-bytecode hello.js

image.png

3.8.热点代码

首先判断字节码是否为热点代码。通常第一次执行的字节码,Ignition 解释器会逐条解释执行。在执行的过程中,如果发现是热点代码,比如for 循环中的代码被执行了多次,这种就称之为热点代码。那么后台的TurboFan就会把该段热点代码编译为高效的机器码,然后再次执行这段被优化的代码时,只需要执行编译后的机器码就可以了, 这样就大大提升了代码的执行效率。

3.9.编译器

TurboFan编译器也可以说是JIT的即时编译器,也可以说是优化编译器。

Ignition 解释器: 可以将AST生成字节码,还可以解释执行字节码。

4、总结

  • 了解V8整个的运行机制
  • 学习JavaScript到底是怎么运行的
  • 对日后编写JavaScript代码有非常多的好处
  • 看完学习了,能提升我们的技术水平
  • 对于日后遇到问题,能够从底层去思考问题出在那里,更快速的定位和解决问题
  • 真的非常熟悉了,可以自己开发一门新的语言