本篇文章主要是站在 JavaScript 引擎 V8 的视角,来分析 JavaScript 代码是如何被执行的。

前端工具和框架的自身更新速度非常块,而且还不断有新的出现。要想追赶上前端工具和框架的更新速度,就需要抓住那些本质的知识,然后才能更加轻松地理解这些上层应用。比如我们接下来要介绍的 V8 执行机制,从底层了解 JavaScript,深入理解语言转换器 Babel、语法检查工具 ESLint、前端框架 Vue 和 React 的一些底层实现机制。因此,了解 V8 的编译流程能让我们对语言以及相关工具有更加充分的认识。

要深入理解 V8 的工作原理,就需要搞清楚一些概念和原理,比如编译器(Compiler)、解释器(Interpreter)、抽象语法树(AST)、字节码(Bytecode)、即时编译器(JIT)等概念,都是需要重点关注的。

编译器和解释器

之所以存在编译器和解释器,是因为机器不能直接理解我们所写的代码,所以在执行程序之前,需要将我们所写的代码“翻译”成机器能读懂的机器语言。按语言的执行流程,可以把语言划分为编译型语言和解释型语言。

编译型语言在程序执行之前,需要经过编译器的编译过程,并且编译之后会直接保留机器能读懂的二进制文件,这样每次运行程序时,都可以直接运行该二进制文件,而不需要再次重新编译了。比如 C/C++、GO 等都是编译型语言。

而由解释型语言编写的程序,在每次运行时都需要通过解释器对程序进行动态解释和执行。比如 Python、JavaScript 等都属于解释型语言。

那编译器和解释器是如何“翻译”代码的呢?具体流程可以参考下图

从图中可以看出这二者的执行流程,大致可阐述为如下:

在编译型语言的编译过程中,编译器首先会依次对源代码进行词法分析、语法分析,生成抽象语法树(AST),然后是优化代码,最后再生成处理器能够理解的机器码。如果编译成功,将会生成一个可执行的文件。但如果编译过程发生了语法或者其他的错误,那么编译器就会抛出异常,最后的二进制文件也不会生成成功
在解释型语言的解释过程中,同样解释器也会对源代码进行词法分析、语法分析,并生成抽象语法树(AST),不过它会再基于抽象语法树生成字节码,最后再根据字节码来执行程序、输出结果。

V8 是如何执行一段 JavaScript 代码的

接下来重点分析下 V8 是如何执行一段 JavaScript 代码的。参考下图:

从图中可以清楚地看到,V8 在执行过程中既有解释器 Ignition,又有编译器 TurboFan,那么它们是如何配合去执行一段 JavaScript 代码的呢?

1. 生成抽象语法树(AST)和执行上下文

将源代码转换为抽象语法树,并生成执行上下文,主要是代码在执行过程中的环境信息。

那么下面重点讲解下抽象语法树(下面表述中就直接用它的简称 AST 了),看看什么是 AST 以及 AST 的生成过程是怎样的。

高级语言是开发者可以理解的语言,但是让编译器或者解释器来理解就非常困难了。对于编译器或者解释器来说,它们可以理解的就是 AST 了。所以无论你使用的是解释型语言还是编译型语言,在编译过程中,它们都会生成一个 AST。这和渲染引擎将 HTML 格式文件转换为计算机可以理解的 DOM 树的情况类似。

可以结合下面这段代码来直观地感受下什么是 AST:

var myName = " fuyou "
function foo(){return 23;
}
myName = "fuyoubenzun"
foo()

这段代码经过javascript-ast站点处理后,生成的 AST 结构。AST 的结构和代码的结构非常相似,可以把 AST 看成代码的结构化的表示,编译器或者解释器后续的工作都需要依赖于 AST,而不是源代码。

AST 是非常重要的一种数据结构,在很多项目中有着广泛的应用。其中最著名的一个项目是 Babel。Babel 是一个被广泛使用的代码转码器,可以将 ES6 代码转为 ES5 代码,这意味着可以现在就用 ES6 编写程序,而不用担心现有环境是否支持 ES6。Babel 的工作原理就是先将 ES6 源码转换为 AST,然后再将 ES6 语法的 AST 转换为 ES5 语法的 AST,最后利用 ES5 的 AST 生成 JavaScript 源代码。

除了 Babel 外,还有 ESLint 也使用 AST。ESLint 是一个用来检查 JavaScript 编写规范的插件,其检测流程也是需要将源码转换为 AST,然后再利用 AST 来检查代码规范化的问题。

AST 是如何生成的?通常,生成 AST 需要经过两个阶段。

第一阶段是分词(tokenize),又称为词法分析,其作用是将一行行的源码拆解成一个个 token。所谓token,指的是语法上不可能再分的、最小的单个字符或字符串。

第二阶段是解析(parse),又称为语法分析,其作用是将上一步生成的 token 数据,根据语法规则转为 AST。如果源码符合语法规则,这一步就会顺利完成。但如果源码存在语法错误,这一步就会终止,并抛出一个“语法错误”。

这就是 AST 的生成过程,先分词,再解析。

有了 AST 后,那接下来 V8 就会生成该段代码的执行上下文。至于执行上下文的具体内容,可以参考前面几篇文章的讲解。

2. 生成字节码

有了 AST 和执行上下文后,那接下来的第二步,解释器 Ignition 就登场了,它会根据 AST 生成字节码,并解释执行字节码。

其实一开始 V8 并没有字节码,而是直接将 AST 转换为机器码,由于执行机器码的效率是非常高效的,所以这种方式在发布后的一段时间内运行效果是非常好的。但是随着 Chrome 在手机上的广泛普及,特别是运行在 512M 内存的手机上,内存占用问题也暴露出来了,因为 V8 需要消耗大量的内存来存放转换后的机器码。为了解决内存占用问题,V8 团队大幅重构了引擎架构,引入字节码,并且抛弃了之前的编译器,最终花了将进四年的时间,实现了现在的这套架构。

那什么是字节码呢?为什么引入字节码就能解决内存占用问题呢?

字节码就是介于 AST 和机器码之间的一种代码。但是与特定类型的机器码无关,字节码需要通过解释器将其转换为机器码后才能执行。

理解了什么是字节码,再对比下高级代码、字节码和机器码,机器码所占用的空间远远超过了字节码,所以使用字节码可以减少系统的内存使用。

3. 执行代码

生成字节码之后,接下来就要进入执行阶段了。

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

V8 的解释器和编译器的取名也很有意思。解释器 Ignition 是点火器的意思,编译器 TurboFan 是涡轮增压的意思,寓意着代码启动时通过点火器慢慢发动,一旦启动,涡轮增压介入,其执行效率随着执行时间越来越高效率,因为热点代码都被编译器 TurboFan 转换了机器码,直接执行机器码就省去了字节码“翻译”为机器码的过程。

其实字节码配合解释器和编译器是最近一段时间很火的技术,比如 Java 和 Python 的虚拟机也都是基于这种技术实现的,这种技术称为即时编译(JIT)。具体到 V8,就是指解释器 Ignition 在解释执行字节码的同时,收集代码信息,当它发现某一部分代码变热了之后,TurboFan 编译器便闪亮登场,把热点的字节码转换为机器码,并把转换后的机器码保存起来,以备下次使用。

对于 JavaScript 工作引擎,除了 V8 使用了“字节码 +JIT”技术之外,苹果的 SquirrelFish Extreme 和 Mozilla 的 SpiderMonkey 也都使用了该技术。

这么多语言的工作引擎都使用了“字节码 +JIT”技术,因此理解 JIT 这套工作机制还是很有必要的。你可以结合下图看看 JIT 的工作过程:

JavaScript 的性能优化

在过去几年中,JavaScript 的性能得到了大幅提升,这得益于 V8 团队对解释器和编译器的不断改进和优化。

虽然在 V8 诞生之初,也出现过一系列针对 V8 而专门优化 JavaScript 性能的方案,比如隐藏类、内联缓存等概念都是那时候提出来的。不过随着 V8 的架构调整,越来越不需要这些微优化策略了,相反,对于优化 JavaScript 执行效率,应该将优化的中心聚焦在单次脚本的执行时间和脚本的网络下载上,主要关注以下三点内容

  • 提升单次脚本的执行速度,避免 JavaScript 的长任务霸占主线程,这样可以使得页面快速响应交互;
  • 避免大的内联脚本,因为在解析 HTML 的过程中,解析和编译也会占用主线程;
  • 减少 JavaScript 文件的容量,因为更小的文件会提升下载速度,并且占用更低的内存

在编译器和解释器中V8是如何执行一段JavaScript代码的?相关推荐

  1. V8引擎:编译器和解析器是如何执行一段javascript代码的?

    前言 前面我已经说完了js引擎是如何存储数据,如何回收垃圾的,但这只是基础罢了,并不是v8引擎的最主要任务,接下来我要讲v8引擎的核心:如何执行js代码,为什么要学习这些东西呢? 前端工具和框架的自身 ...

  2. 图解 Google V8 # 01:V8 是如何执行一段 JavaScript 代码的?

    说明 图解 Google V8 学习笔记 JavaScript 的设计思想 JavaScript 借鉴了很多语言的特性: C 语言的基本语法 Java 的类型系统和内存管理 Scheme 的函数作为一 ...

  3. 移动网站开发中常用的10段JavaScript代码

    在开发移动网站过程中,有一些Javascript代码会经常用到.以下是10段常用的JavaScript代码.需要注意的是某几段代码需要jQuery mobile framework支持. 1.如果网页 ...

  4. 网页制作中最有用的免费Ajax和JavaScript代码库

    本文中,小编整理了12个免费的Ajax和JavaScript代码库,可以帮助Web开发人员将应用程序提升到一个新水平. Ajax Instant Messenger 它是最流行和常用的Ajax代码解决 ...

  5. AJAX异步从优酷专辑中采集所有视频及信息(JavaScript代码)

    上次写了一个 .NET从优酷专辑中采集所有视频及信息(VB.NET代码) http://www.cnblogs.com/clso/archive/2010/01/09/1642952.html 个人觉 ...

  6. V8 工作原理之编译器和解释器

    V8 工作原理之编译器和解释器 要深入理解 V8 的工作原理,你需要搞清楚一些概念和原理,比如接下来我们要详细讲解的**编译器(Compiler).解释器(Interpreter).抽象语法树(AST ...

  7. JS编程建议——2:正确辨析JavaScript句法中的词、句和段

    建议2:正确辨析JavaScript句法中的词.句和段 JavaScript语法包含了合法的JavaScript代码的所有规则和特征,它主要分为词法和句法.词法包括字符编码.名词规则.特殊词规则等.词 ...

  8. html中写一个占内存很大死循环代码,HTML5新特性Bug:这12行代码分分钟让你浏览器崩溃iPhone重启...

    使用这十二行JavaScript代码能让firefox.chrome.safari等众多浏览器崩溃,甚至让iPhone重启? 起因 今天刷推特的时候发现Cyber Security@cyber__se ...

  9. jslint4java_在Eclipse中使用JSLint保证JavaScript代码质量

    JSLint简介 JavaScript 作为一门语法灵活多变且对格式要求相对松散的语言,代码格式的混乱和某些语言特性的不正确使用,往往使得最终交付的产品中包含许多因编码风格约定造成的未预见的行为或错误 ...

最新文章

  1. 4月份阿里云ECS和VPC升级公告
  2. jenkins blue ocean 与 pipeline
  3. SKIP-NAME-RESOLVE ——错误的使用时机造成用户权限
  4. mssql 2008恢复xp_cmdshell
  5. 修改 gcc 和 g++ 的默认版本
  6. 海上瓶子下有东西吗_《海上钢琴师》:宁愿一生孤独,不愿随波逐流。
  7. jsmin php,使用JSMin.php缩小Javascript
  8. 好家伙!QQ正在读取你所有的浏览器历史记录?腾讯致歉后,网友评论绝了
  9. 常用的Ant风格书写
  10. 计算机tlv简介_TLV编码格式详解
  11. 算法 Tricks(六)—— 判断一个数是否为完全平方数
  12. WebLogic如何设置session超时时间
  13. dicom worklist下载病例程序/dicom worklist scu (c#版本)
  14. 虚拟麦克风音频输入_Audio Precision 全新声学/音频分析软件可减少测试时间
  15. sxe增加服务器,sXe Injected 反作弊插件
  16. 1.5 设置新建工作簿的默认属性 [原创Excel教程]
  17. 计算机休眠唤醒原理,电脑休眠和睡眠区别以及怎么唤醒
  18. ElementPlus 侧边栏右侧空隙
  19. Android 修改系统屏幕亮度
  20. sbrkr.c:(.text._sbrk_r+0xc): undefined reference to `_sbrk'

热门文章

  1. 判断在直线的左边右边c语言,正确驾驶姿势
  2. 【推荐系统】Graph Embedding系列之EGES: Billion-scale Commodity Embedding for E-commerce Recommend in Alibaba
  3. 10.OP-TEE OS启动(一)
  4. 《计算机操作系统》课程学习(1)——第1章 操作系统引论
  5. 智伴机器人或阿尔法蛋_想激发宝宝潜能,如何挑选AI教育机器人?
  6. 重庆自考本科可以选择全日制吗?
  7. 【服务器数据恢复】服务器RAID0+1数据恢复案例
  8. 基于单片机的酒精浓度测试仪的设计
  9. shellcode之360安全卫士免杀(shecodject)(一)
  10. 包贝尔婚礼事件中,有哪些嘈可以吐?