Skip to content

Js引擎

从头到尾负责整个JavaScript程序的编译及执行过程。

前言

不知道大家有没有想过这样一个问题,我们所写的 JavaScript 代码是怎样被计算机认识并且执行的呢?这中间的过程具体是怎样的呢?

V8引擎

有的同学可能已经知道,Js 是通过 Js 引擎运行起来的,那么

  • 什么是 Js 引擎?
  • Js 引擎是怎样编译执行和优化 Js 代码的?

Js 引擎有很多种,比如 Chrome 使用的 V8 引擎,Webkit 使用的是 JavaScriptCore,React Native 使用的是 Hermes。今天我们主要来分析一下比较主流的 V8 引擎是怎样运行 Js 的。

V8 引擎

在介绍 V8 引擎的概念之前,我们先来回顾一下编程语言。编程语言可以分为机器语言、汇编语言、高级语言。

编程语言

  • 机器语言:由 0 和 1 组成的二进制码,对于人类来说是很难记忆的,还要考虑不同 CPU 平台的兼容性。
  • 汇编语言:用更容易记忆的英文缩写标识符代替二进制指令,但还是需要开发人员有足够的硬件知识。
  • 高级语言:更简单抽象且不需要考虑硬件,但是需要更复杂、耗时更久的翻译过程才能被执行。

到了这里我们知道,高级语言一定要转化为机器语言才能被计算机执行,而且越高级的语言转化的时间越久。高级语言又可以分为解释型语言、编译型语言。

解释代码 vs 编译代码

作为程序员,你或许听说过这两个术语:解释(interpret)和编译(compile)。在解释型语言中,代码自上而下运行,且实时返回运行结果。代码在由浏览器执行前,不需要将其转化为其他形式。代码将直接以文本格式被接收和处理。

相对的,编译型语言需要先将代码转化(编译)成另一种形式才能运行。比如 C/C++ 先被编译成机器码,然后才能由计算机运行。程序将以二进制的格式运行,这些二进制内容是由程序源代码产生的。

JavaScript 是轻量级解释型语言。浏览器接受到 JavaScript 代码,并以代码自身的文本格式运行它。技术上,几乎所有 JavaScript 转换器都运用了一种叫做即时编译(just-in-time compiling)的技术;当 JavaScript 源代码被执行时,它会被编译成二进制的格式,使代码运行速度更快。尽管如此,JavaScript 仍然是一门解释型语言,因为编译过程发生在代码运行中,而非之前。

  • 编译型语言:需要编译器进行一次编译,被编译过的文件可以多次执行。如 C++、C 语言。
  • 解释型语言:不需要事先编译,通过解释器一边解释一边执行。启动快,但执行慢。

我们知道 JavaScript 是一门高级语言,并且是动态类型语言,我们在定义一个变量时不需要关心它的类型,并且可以随意的修改变量的类型。而在像 C++这样的静态类型语言中,我们必须提前声明变量的类型并且赋予正确的值才行。也正是因为 JavaScript 没有像 C++那样可以事先提供足够的信息供编译器编译出更加低级的机器代码,它只能在运行阶段收集类型信息,然后根据这些信息进行编译再执行,所以 JavaScript 也是解释型语言。

这也就意味着 JavaScript 要想被计算机执行,需要一个能够快速解析并且执行 JavaScript 脚本的程序,这个程序就是我们平时所说的 JavaScript 引擎。这里我们给出 V8 引擎的概念:V8 是 Google 基于 C++ 编写的开源高性能 Javascript 与 WebAssembly 引擎。用于 Google Chrome(Google 的开源浏览器) 以及 Node.js 等。

V8 引擎的编译流水线

接下来我们先从宏观的角度来看一下 V8 是怎么执行 JavaScript 代码的,然后再对每一步进行分析。

  • 初始化基础环境;
  • 解析源码生成 AST 和作用域;
  • 依据 AST 和作用域生成字节码;
  • 解释执行字节码;监听热点代码;
  • ...

V8引擎的编译流水线

运行时环境为 V8 提供了堆空间,栈空间、全局执行上下文、消息循环系统、宿主对象及宿主 API 等。V8 的核心是实现了 ECMAScript 标准,此外还提供了垃圾回收器等内容。

宿主&V8


参考文章和部分图片来源: Js是怎样运行起来的?