JavaScript的工作原理:解析、抽象语法树+ 提升编译速度5个技巧

JavaScript 启动性能瓶颈分析与解决方案

2017/02/17 · JavaScript
· 性能

原文出处: Addy
Osmani   译文出处:王下邀月熊_Chevalier   

图片 1

在 Web 开发中,随着需求的增加与代码库的扩张,我们最终发布的 Web
页面也逐渐膨胀。不过这种膨胀远不止意味着占据更多的传输带宽,其还意味着用户浏览网页时可能更差劲的性能体验。浏览器在下载完某个页面依赖的脚本之后,其还需要经过语法分析、解释与运行这些步骤。而本文则会深入分析浏览器对于
JavaScript
的这些处理流程,挖掘出那些影响你应用启动时间的罪魁祸首,并且根据我个人的经验提出相对应的解决方案。回顾过去,我们还没有专门地考虑过如何去优化
JavaScript
解析/编译这些步骤;我们预想中的是解析器在发现<script>标签后会瞬时完成解析操作,不过这很明显是痴人说梦。下图是对于
V8 引擎工作原理的概述:
图片 2下面我们深入其中的关键步骤进行分析。

在 Web 开发中,随着需求的增加与代码库的扩张,我们最终发布的 Web
页面也逐渐膨胀。不过这种膨胀远不止意味着占据更多的传输带宽,其还意味着用户浏览网页时可能更差劲的性能体验。浏览器在下载完某个页面依赖的脚本之后,还需要经过语法分析、解释与运行这些步骤。而本文则会深入分析浏览器对于
JavaScript
的这些处理流程,挖掘出那些影响你应用启动时间的罪魁祸首,并且根据我个人的经验提出相对应的解决方案。回顾过去,我们还没有专门地考虑过如何去优化
JavaScript
解析/编译这些步骤;我们预想中的是解析器在发现<script>标签后会瞬时完成解析操作,不过这很明显是痴人说梦。下图是对于
V8 引擎工作原理的概述:

摘要:JS的”编译原理”。

到底是什么拖慢了我们应用的启动时间?

在启动阶段,语法分析,编译与脚本执行占据了 JavaScript
引擎运行的绝大部分时间。换言之,这些过程造成的延迟会真实地反应到用户可交互时延上;譬如用户已经看到了某个按钮,但是要好几秒之后才能真正地去点击操作,这一点会大大影响用户体验。
图片 3上图是我们使用
Chrome Canary 内置的 V8 RunTime Call Stats
对于某个网站的分析结果;需要注意的是桌面浏览器中语法解析与编译占用的时间还是蛮长的,而在移动端中占用的时间则更长。实际上,对于
Facebook, Wikipedia, Reddit
这些大型网站中语法解析与编译所占的时间也不容忽视:
图片 4上图中的粉色区域表示花费在
V8 与 Blink’s C++
中的时间,而橙色和黄色分别表示语法解析与编译的时间占比。Facebook 的
Sebastian Markbage 与 Google 的 Rob Wormald 也都在 Twitter 发文表示过
JavaScript 的语法解析时间过长已经成为了不可忽视的问题,后者还表示这也是
Angular 启动时主要的消耗之一。
图片 5

随着移动端浪潮的涌来,我们不得不面对一个残酷的事实:移动端对于相同包体的解析与编译过程要花费相当于桌面浏览器2~5倍的时间。当然,对于高配的
iPhone 或者 Pixel 这样的手机相较于 Moto G4
这样的中配手机表现会好很多;这一点提醒我们在测试的时候不能仅用身边那些高配的手机,而应该中高低配兼顾:
图片 6

上图是部分桌面浏览器与移动端浏览器对于 1MB 的 JavaScript
包体进行解析的时间对比,显而易见的可以发现不同配置的移动端手机之间的巨大差异。当我们应用包体已经非常巨大的时候,使用一些现代的打包技巧,譬如代码分割,TreeShaking,Service
Workder
缓存等等会对启动时间有很大的影响。另一个角度来看,即使是小模块,你代码写的很糟或者使用了很糟的依赖库都会导致你的主线程花费大量的时间在编译或者冗余的函数调用中。我们必须要清醒地认识到全面评测以挖掘出真正性能瓶颈的重要性。

图片 7

  • 原文:JavaScript的工作原理:解析、抽象语法树+ 提升编译速度5个技巧

JavaScript 语法解析与编译是否成为了大部分网站的瓶颈?

我曾不止一次听到有人说,我又不是 Facebook,你说的 JavaScript
语法解析与编译到
底会对其他网站造成什么样的影响呢?对于这个问题我也很好奇,于是我花费了两个月的时间对于超过
6000 个网站进行分析;这些网站囊括了 React,Angular,Ember,Vue
这些流行的框架或者库。大部分的测试是基于 WebPageTest
进行的,因此你可以很方便地重现这些测试结果。光纤接入的桌面浏览器大概需要
8 秒的时间才能允许用户交互,而 3G 环境下的 Moto G4 大概需要 16 秒
才能允许用户交互。

图片 8大部分应用在桌面浏览器中会耗费约
4 秒的时间进行 JavaScript 启动阶段(语法解析、编译、执行)

图片 9

而在移动端浏览器中,大概要花费额外 36% 的时间来进行语法解析:
图片 10

另外,统计显示并不是所有的网站都甩给用户一个庞大的 JS
包体,用户下载的经过 Gzip 压缩的平均包体大小是 410KB,这一点与
HTTPArchive 之前发布的 420KB
的数据基本一致。不过最差劲的网站则是直接甩了 10MB
的脚本给用户,简直可怕。

图片 11

通过上面的统计我们可以发现,包体体积固然重要,但是其并非唯一因素,语法解析与编译的耗时也不一定随着包体体积的增长而线性增长。总体而言小的
JavaScript
包体是会加载地更快(忽略浏览器、设备与网络连接的差异),但是同样 200KB
的大小,不同开发者的包体在语法解析、编译上的时间却是天差地别,不可同日而语。

image.png

Fundebug经授权转载,版权归原作者所有。

现代 JavaScript 语法解析 & 编译性能评测

下面我们深入其中的关键步骤进行分析。

这是专门探索 JavaScript 及其所构建的组件的系列文章的第 14 篇。

Chrome DevTools

打开 Timeline( Performance panel ) > Bottom-Up/Call Tree/Event Log
就会显示出当前网站在语法解析/编译上的时间占比。如果你希望得到更完整的信息,那么可以打开
V8 的 Runtime Call Stats。在 Canary 中,其位于 Timeline 的 Experims >
V8 Runtime Call Stats 下。
图片 12

到底是什么拖慢了我们应用的启动时间?

在启动阶段,语法分析、编译与脚本执行占据了 JavaScript
引擎运行的绝大部分时间。换言之,这些过程造成的延迟会真实地反应到用户可交互时延上;譬如用户已经看到了某个按钮,但是要好几秒之后才能真正地去点击操作,这一点会大大影响用户体验。下图是我们使用
Chrome Canary 内置的 V8 RunTime Call Stats 对于某个网站的分析结果:

图片 13

image.png

需要注意的是桌面浏览器中语法解析与编译占用的时间还是蛮长的,而在移动端中占用的时间则更长。实际上,对于
Facebook, Wikipedia, Reddit
这些大型网站中语法解析与编译所占的时间也不容忽视,下图中的粉色区域表示花费在
V8 与 Blink’s C++
中的时间,而橙色和黄色分别表示语法解析与编译的时间占比:

图片 14

image.png

Facebook 的 Sebastian Markbage 与 Google 的 Rob Wormald 也都在 Twitter
发文表示过 JavaScript
的语法解析时间过长已经成为了不可忽视的问题,后者还表示这也是 Angular
启动时主要的消耗之一。

图片 15

image.png

随着移动端浪潮的涌来,我们不得不面对一个残酷的事实:移动端对于相同包体的解析与编译过程要花费相当于桌面浏览器2~5倍的时间。当然,对于高配的
iPhone 或者 Pixel 这样的手机相较于 Moto G4
这样的中配手机表现会好很多;这一点提醒我们在测试的时候不能仅用身边那些高配的手机,而应该中高低配兼顾:

图片 16

image.png

上图是部分桌面浏览器与移动端浏览器对于 1MB 的 JavaScript
包体进行解析的时间对比,显而易见的可以发现不同配置的移动端手机之间的巨大差异。当我们应用包体已经非常巨大的时候,使用一些现代的打包技巧,譬如代码分割,TreeShaking,Service
Workder
缓存,等等会对启动时间有很大的影响。另一个角度来看,即使是小模块,你代码写的很糟或者使用了很糟的依赖库都会导致你的主线程花费大量的时间在编译或者冗余的函数调用中。我们必须要清醒地认识到全面评测以挖掘出真正性能瓶颈的重要性。

如果你错过了前面的章节,可以在这里找到它们:

Chrome Tracing

打开 about:tracing 页面,Chrome
提供的底层的追踪工具允许我们使用disabled-by-default-v8.runtime_stats来深度了解
V8 的时间消耗情况。V8
也提供了详细的指南来介绍如何使用这个功能。
图片 17

JavaScript 语法解析与编译是否成为了大部分网站的瓶颈?

我曾不止一次听到有人说,我又不是 Facebook,你说的 JavaScript
语法解析与编译到底会对其他网站造成什么样的影响呢?对于这个问题我也很好奇,于是我花费了两个月的时间对于超过
6000 个网站进行分析;这些网站囊括了 React,Angular,Ember,Vue
这些流行的框架或者库。大部分的测试是基于 WebPageTest
进行的,因此你可以很方便地重现这些测试结果。光纤接入的桌面浏览器大概需要
8 秒的时间才能允许用户交互,而 3G 环境下的 Moto G4 大概需要 16 秒
才能允许用户交互。

图片 18

image.png

大部分应用在桌面浏览器中会耗费约 4 秒的时间进行 JavaScript
启动阶段(语法解析、编译、执行):

图片 19

image.png

而在移动端浏览器中,大概要花费额外 36% 的时间来进行语法解析:

图片 20

image.png

另外,统计显示并不是所有的网站都甩给用户一个庞大的 JS
包体,用户下载的经过 Gzip 压缩的平均包体大小是 410KB,这一点与
HTTPArchive 之前发布的 420KB
的数据基本一致。不过最差劲的网站则是直接甩了 10MB
的脚本给用户,简直可怕。

图片 21

image.png

通过上面的统计我们可以发现,包体体积固然重要,但是其并非唯一因素,语法解析与编译的耗时也不一定随着包体体积的增长而线性增长。总体而言小的
JavaScript
包体是会加载地更快(忽略浏览器、设备与网络连接的差异),但是同样 200KB
的大小,不同开发者的包体在语法解析、编译上的时间却是天差地别,不可同日而语。

  • JavaScript 是如何工作的:引擎,运行时和调用堆栈的概述!

  • JavaScript 是如何工作的:深入V8引擎&编写优化代码的5个技巧!

  • JavaScript 是如何工作的:内存管理+如何处理4个常见的内存泄漏 !

  • JavaScript 是如何工作的:事件循环和异步编程的崛起+ 5种使用
    async/await 更好地编码方式!

  • JavaScript 是如何工作的:深入探索 websocket 和HTTP/2与SSE
    +如何选择正确的路径!

  • JavaScript 是如何工作的:与 WebAssembly比较 及其使用场景 !

  • JavaScript 是如何工作的:Web Workers的构建块+ 5个使用他们的场景!

  • JavaScript 是如何工作的:Service Worker 的生命周期及使用场景!

  • JavaScript 是如何工作的:Web 推送通知的机制!

  • JavaScript是如何工作的:使用 MutationObserver 跟踪 DOM 的变化!

  • JavaScript是如何工作的:渲染引擎和优化其性能的技巧!

  • JavaScript是如何工作的:深入网络层 + 如何优化性能和安全!

  • JavaScript是如何工作的:CSS 和 JS
    动画底层原理及如何优化它们的性能!-

WebPageTest

图片 22WebPageTest
中 Processing Breakdown 页面在我们启用 Chrome > Capture Dev Tools
Timeline 时会自动记录 V8 编译、EvaluateScript 以及 FunctionCall
的时间。我们同样可以通过指明disabled-by-default-v8.runtime_stats的方式来启用
Runtime Call Stats。
图片 23

更多使用说明参考我的gist点击预览。

现代 JavaScript 语法解析 & 编译性能评测

概述

我们都知道运行一大段 JavaScript
代码性能会变得很糟糕。这段代码不仅需要通过网络传输,而且还需要解析、编译成字节码,最后执行。在之前的文章中,我们讨论了
JS 引擎、运行时和调用堆栈等,以及主要由谷歌 Chrome 和 NodeJS
使用的V8引擎。它们在整个 JavaScript
执行过程中都发挥着至关重要的作用。这篇说的抽象语法树同样重要:在这我们将了解大多数
JavaScript
引擎如何将文本解析为对机器有意义的内容,转换之后发生的事情以及做为 Web
开发者如何利用这一知识。

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website