Lynx

小熊写字的地方

马上订阅 Lynx RSS 更新: https://blog.skrskrskrskr.com/atom.xml

【译】2019 年的 JavaScript 性能

2019年7月6日 11:41

建议阅读本文前先读完这篇文章:使用Script-Streaming提升页面加载性能

原文作者:Addy Osmani (@addyosmani[1])

过去几年中,JavaScript 性能[2]的大幅改进很大程度上依赖于浏览器解析和编译 JavaScript 的速度。2019 年,处理 JavaScript 的主要性能损耗在于下载和 CPU 执行时间。

浏览器主线程忙于执行 JavaScript 时,用户交互会被延迟,因此脚本执行时间和网络上的瓶颈优化尤其重要。

可行的高级指南


这对于 web 开发者意味着什么?解析和编译的性能损耗不再像从前我们认为的那样慢。我们需要关注三点:

提升下载速度

•减小 JavaScript 包的体积,尤其是在移动设备上。更小的包可以提升下载速度,带来更低的内存占用,并减少 CPU 性能损耗。•避免把代码打包成一个大文件。如果一个包超过 50–100 kB,把它分割成多个更小的包。(由于 HTTP/2 的多路复用特性,多个请求和响应可以同时到达,从而减少额外请求的负载。)•由于移动设备上的网络速度,你应该减少网络传输,而且也需要维持更低的内存使用。

提升执行速度

•避免使主线程忙碌的长任务[3],使页面快点进行可交互态。脚本执行时间目前成为了一个主要的性能损耗。

避免大型内联脚本(因为它们也会在主线程中解析和编译)一个不错的规定是:如果脚本超过 1KB,就不要将其内联(也因为外部脚本的字节码缓存[4]要求最小为 1KB)。

为何优化下载和执行时间很重要?


为何优化下载和执行时间很重要?下载时间在低端网络环境下很关键。尽管 4G(甚至 5G)在全球范围快速发展,我们实际感受到的网络速度[5]和宣传并不一致,很多时候感觉就像 3G(甚至更差)。

JavaScript 执行时间在使用低端 CPU 的手机上很重要。由于 CPU、GPU 和散热上的差异,不同手机上性能差异非常大。这会影响到 JavaScript 的性能,因为 JavaScript 的执行是 CPU 密集型任务。

实际上,像 Chrome 这样的浏览器上的页面加载总时间,有多达 30% 的时间花在 JavaScript 执行上。下面是一个很典型的网站(Reddit.com)在高端桌面设备上的页面加载,

image

V8 中的 JavaScript 处理占用了页面加载时间的 10-30%

移动设备上,中端机(Moto G4)的 JavaScript 执行时间是高端机(Pixel 3)的 3 到 4 倍,低端机(不到100 刀的 Alcatel 1X)上有超过 6 倍的性能差异:

image

Reddit 在不同设备类型上(低端、中端和高端)的 JavaScript 性能损耗

注意:Reddit 在桌面端和移动端的体验完全不同,因此 MacBook Pro 上的结果并不能和其他设备上的结果直接做比较。

当你尝试优化 JavaScript 执行时间,注意关注长任务[6],它可能长期独占 UI 线程。这些任务会阻塞执行关键任务,即便页面看起来已经加载完成。把长任务拆分成多个小任务。通过代码分割和指定加载优先级,可以提升页面可交互速度,并且有希望降低输入延迟。

image

长任务独占主线程,应该拆分它们

V8 在提升解析编译速度上做了什么?


Chrome 60+ 上,V8 对于初始 JavaScript 的解析速度提升了 2 倍。与此同时, 由于 Chrome 上的其他并行优化,初始解析和编译的性能损耗更少了。

V8 减少了主线程上的解析编译任务,平均减少了 40%(比如 Facebook 上是 46%,Pinterest 上是 62%),最高减少了 81%(YouTube),这得益于将解析编译任务搬到了 worker 线程上。这对于流式解析/编译[7]是一个补充。

image

不同 V8 版本上的解析时间

下图形象呈现了不同 Chrome V8 版本上 CPU 解析时间。Chrome 61 解析 Facebook 的 JS 所花的时间里,Chrome 75 可以解析 Facebook 和6次 Twitter。

image

我们来研究下这些释放出来的改变。简言之,流式解析和 worker 线程编译脚本,这意味着:

•V8 可以解析编译 JavaScript 时不阻塞主线程。•流式解析始于整个 HTML 解析器遇到 <script> 标签。对于阻塞解析的 JS,HTML 解析器会暂停,而异步 JS 会继续执行。•大多数真实世界的网络连接速度下,V8 解析比下载快,所以 V8 在 JS 下载完后很快就完成了解析编译。

稍微解释下…很老的 Chrome 上会在全部下载完 JS 后才开始解析,这很直接但并没有完全利用好 CPU。Chrome 41 和 68 之间的版本上,Chrome 在下载一开始就在一个独立线程上解析 async 和 defer 的 JavaScript。

image

页面上的 JavaScript 代码被分割成多个块。V8 只会对超过 30KB...

剩余内容已隐藏

查看完整文章以阅读更多