<audio id="audio" title="开篇词 | 如何学习谷歌高性能 JavaScript 引擎V8？" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/ef/b1/ef76d1d1048d55598e0b0b8b761891b1.mp3"></audio>

你好，我是李兵，《[浏览器工作原理与实践](https://time.geekbang.org/column/intro/216?utm_term=zeusQYFJN&amp;utm_source=app&amp;utm_medium=geektime&amp;utm_campaign=216-end&amp;utm_content=v8zhuanlankaipianci0316)》专栏的作者。在浏览器专栏中，我们对浏览器的工作原理进行了详细的介绍，其中也提到了V8是如何执行JavaScript代码的。很多朋友对这部分的学习意犹未尽，因此我又回到了极客时间，与你深入聊聊V8。

## 什么是V8？

V8是JavaScript虚拟机的一种。我们可以简单地把JavaScript虚拟机理解成是一个翻译程序，将人类能够理解的**编程语言JavaScript**，翻译成机器能够理解的**机器语言**。如下图所示：

<img src="https://static001.geekbang.org/resource/image/8a/a1/8a40fd003baa9be179fe2e55a1be5fa1.jpg" alt="" title="JavaScript引擎">

上图中，中间的“黑盒”就是JavaScript引擎V8。目前市面上有很多种JavaScript引擎，诸如SpiderMonkey、V8、JavaScriptCore等。而由谷歌开发的开源项目V8是当下使用最广泛的JavaScript虚拟机，全球有超过25亿台安卓设备，而这些设备中都使用了Chrome浏览器，所以我们写的JavaScript应用，大都跑在V8上。

V8之所以拥有如此庞大的生态圈，也和它许多革命性的设计是分不开的。

在V8出现之前，所有的JavaScript虚拟机所采用的都是解释执行的方式，这是JavaScript执行速度过慢的一个主要原因。而V8率先引入了即时编译（JIT）的双轮驱动的设计，这是一种权衡策略，混合编译执行和解释执行这两种手段，给JavaScript的执行速度带来了极大的提升。

V8出现之后，各大厂商也都在自己的JavaScript虚拟机中引入了JIT机制，所以你会看到目前市面上JavaScript虚拟机都有着类似的架构。另外，V8也是早于其他虚拟机引入了惰性编译、内联缓存、隐藏类等机制，进一步优化了JavaScript代码的编译执行效率。

可以说，V8的出现，将JavaScript虚拟机技术推向了一个全新的高度。

即便V8具有诸多优点，但我相信对于大部分同学来说，V8虚拟机还只是一个黑盒，我们将一段代码丢给这个黑盒，它便会返回结果，并没有深入了解过它的工作原理。

如果只是单纯使用JavaScript和调用 Web  API，并不了解虚拟机内部是怎样工作的，在项目中遇到的很多问题很可能找不到解决的途径。比如，有时项目的占用内存过高，或者页面响应速度过慢，又或者使用Node.js的时候导致任务被阻塞等问题，都与V8的基本运行机制有关。如果你熟悉V8的工作机制，就会有系统性的思路来解决这些问题。

另外，V8的主要功能，就是结合JavaScript语言的特性和本质来编译执行它。通过深入地学习V8，你对JavaScript语言本质和设计思想会有很直观的感受。这些设计思想像是更加高级的工具，你掌握了它，就可以提升你的语言使用和架构设计水平。

## 如何学习V8？

那么，我们应该如何来学习V8呢？

刚刚我们也说过，V8的主要职责是用来执行JavaScript代码的，那我们首先需要先了解JavaScript这门语言的基本特性和设计思想。

JavaScript借鉴了很多语言的特性，比如C语言的基本语法、Java的类型系统和内存管理、Scheme的函数作为一等公民，还有Self基于原型（prototype）的继承机制。毫无疑问，JavaScript是一门非常优秀的语言，特别是“原型继承机制”和“函数是一等公民”这两个设计。

<img src="https://static001.geekbang.org/resource/image/f8/7a/f8fb9e3570b88152f9ab7b6b8d385c7a.jpg" alt="" title="JavaScript的设计思想">

不过JavaScript也是一门处处是坑的语言，由于历史原因，很多错误的或者不合理的设计都被延续至今，比如使用new加构造函数来创建对象，这种方式的背后隐藏了太多的细节，非常容易增加代码出错概率，而且也大大增加了新手的学习成本；再比如初期的JavaScript没有块级作用域机制，使得JavaScript需要采取变量提升的策略，而变量提升又是非常反人性的设计。

V8是JavaScript的实现，在学习V8工作原理时，我们就要格外关注JavaScript这些独特的设计思想和特性背后的实现。比如，为了实现函数是一等公民的特性，JavaScript采取了基于对象的策略；再比如为了实现原型继承，V8为每个对象引入了__proto__属性。

**深入分析过JavaScript语言之后，我们就可以学习V8执行JavaScript代码的完整流程了**。我们把这套流程称之为V8的编译流水线，其完整流程如下图所示：

<img src="https://static001.geekbang.org/resource/image/8a/54/8a34ae8c1a7a0f87e19b1384a025e354.jpg" alt="" title="V8编译流水线">

编译流水线本身并不复杂，但是其中涉及到了很多技术，诸如JIT、延迟解析、隐藏类、内联缓存等等。这些技术决定着一段JavaScript代码能否正常执行，以及代码的执行效率。

比如V8中使用的隐藏类（Hide Class），这是将JavaScript中动态类型转换为静态类型的一种技术，可以消除动态类型的语言执行速度过慢的问题，如果你熟悉V8的工作机制，在你编写JavaScript时，就能充分利用好隐藏类这种强大的优化特性，写出更加高效的代码。

再比如，V8实现了JavaScript代码的惰性解析，目的是为了加速代码的启动速度，通过对惰性解析机制的学习，你可以优化你的代码更加适应这个机制，从而提高程序性能。

要想充分了解V8是怎么工作的，除了要分析编译流水线，我们还需要了解另外两个非常重要的特性，那就是**事件循环系统**和**垃圾回收机制。**

事件循环系统和JavaScript中的难点——异步编程特性紧密相关。我们知道，JavaScript是单线程的，JavaScript代码都是在一个线程上执行，如果同一时间发送了多个JavaScript执行的请求，就需要排队，也就是进行异步编程。

V8的事件循环系统会调度这些排队任务，保证JavaScript代码被V8有序地执行。因此也可以说，事件循环系统就是V8的心脏，它驱动了V8的持续工作。

另外，JavaScript是一种自动垃圾回收的语言，V8在执行垃圾回收时，会占用主线程的资源，如果我们编写的程序频繁触发垃圾回收，那么无疑会阻塞主线程，这也是我们经常会遇到的一个问题。你需要知道V8是如何分配内存数据的，以及这些数据是如何被回收的，打通整个链路，建立完整的系统，当下次遇到内存问题时，就知道如何去排查了。

<img src="https://static001.geekbang.org/resource/image/90/43/90228d5cc0afbaaa4cca3fbdb1349243.jpg" alt="" title="V8知识图谱，可以点击放大查看">

以上，就是系统学习V8的路径。在我们这一季的课程中，也会按照这样的思路来设计课程，来帮助你学习到V8的完整的知识体系。

- 首先，我们会从JavaScript的设计思想讲起，讨论它背后的一些主要特性，以及V8是怎么实现这些特性的。
- 然后，我们再来分析V8的编译流水线，在课程中间我们还会穿插介绍一些内存分配相关的内容，因为函数调用、变量声明、参数传递或者函数返回数值都涉及到了内存分配。
- 最后，我们会介绍事件循环系统和垃圾回收系统的工作机制。

<img src="https://static001.geekbang.org/resource/image/26/e3/2684822c6cb6b453c6f4abb3d89822e3.jpg" alt="" title="专栏目录">

虽然本课程的篇幅不多，但是也具有一定的深度和广度。不过你并不需要担心内容太难，我会尽量将每节内容做到深入浅出，有什么问题你可以在留言区提问，我看到后都会第一时间来解答。

另外，在每个模块结束后，我会做一次热点问题的答疑，尽量帮你扫清学习V8的障碍。你需要做的是持之以恒地学习、反思与实践。

加油，从今天起，就让我们一起开始V8的学习旅程吧！
