JavaScript 启动优化

Addy Osmani
Addy Osmani

在构建严重依赖 JavaScript 的网站时,我们有时会在不知不觉中为所发送的内容付费。在本文中,我们将介绍为什么如果您想让网站在移动设备上快速加载和交互,遵守一些规则会有所帮助。减少传递的 JavaScript 数量意味着网络传输所耗费的时间更少,解压缩代码所花费的时间更少,解析和编译此 JavaScript 的时间也更少。

大多数开发者在考虑 JavaScript 的成本时,考虑的都是下载和执行成本。通过网络发送较多的 JavaScript 字节时,用户的连接速度越慢,花费的时间就越长。

当浏览器请求资源时,需要获取并解压缩该资源。对于 JavaScript 等资源,必须先解析和编译这些资源,然后才能执行相应操作。

这可能会是一个问题,因为用户的有效网络连接类型实际上可能不是 3G、4G 或 Wi-Fi。您可以使用咖啡店的 Wi-Fi 网络,但连接到 2G 速度的移动网络热点。

您可以通过以下方式降低 JavaScript 的网络传输费用:

  • 仅发送用户所需的代码
    • 使用代码拆分将 JavaScript 拆分为关键部分和非关键部分。模块打包器(如 webpack)支持代码拆分
    • 延迟加载非关键代码。
  • 缩减大小
  • 压缩
    • 您至少应使用 gzip 压缩基于文本的资源。
    • 请考虑使用 Brotli ~q11。Brotli 在压缩比率方面优于 gzip。它帮助 CertSimple 缩减 17% 的压缩 JS 字节大小,并使用 LinkedIn 缩减 4% 的加载时间。
  • 移除未使用的代码
  • 缓存代码以最大限度地减少网络行程。
    • 使用 HTTP 缓存可确保浏览器有效地缓存响应。确定脚本的最佳生命周期 (max-age),并提供验证令牌 (ETag) 以避免传输未更改的字节。
    • Service Worker 缓存可使您的应用网络具有弹性,并让您能够快速地访问 V8 的代码缓存等功能。
    • 使用长期缓存以避免重新提取尚未更改的资源。如果使用 Webpack,请参阅文件名哈希

解析/编译

下载后,JS 引擎解析/编译此代码的时间是 JavaScript 最大的开销之一。Chrome 开发者工具中,解析和编译是“性能”面板中黄色“脚本”时间的一部分。

ALT_TEXT_HERE

Bottom-Up 和 Call Tree 选项卡显示确切的解析/编译时间:

ALT_TEXT_HERE
Chrome DevTools 的“Performance”(性能)面板 > Bottom-Up。启用 V8 的 Runtime Call Stats 后,我们可以看到在解析和编译等阶段所花费的时间

但是,为什么这很重要?

ALT_TEXT_HERE

花费很长时间来解析/编译代码会严重延迟用户与网站互动的时间。发送的 JavaScript 越多,在网站进入可交互状态之前解析和编译这段代码所需的时间就越长。

就字节而言,浏览器处理 JavaScript 的成本高于同等大小的图片或网页字体 - Tom Dale

与 JavaScript 相比,处理相同大小的图片涉及很多成本(仍然需要解码!),但在普通的移动硬件上,JS 更有可能对页面的交互性产生负面影响。

ALT_TEXT_HERE
JavaScript 和图片字节的费用截然不同。在解码和光栅化图片时,通常不会阻塞主线程或阻止界面互动。但是,JS 可能会因为解析、编译和执行成本而延迟互动。

我们提到解析和编译速度很慢;上下文很重要,在这里我们讨论的是普通手机。普通用户使用的可能是 CPU 和 GPU 速度缓慢、没有 L2/L3 缓存,甚至内存可能受限的手机。

网络功能和设备功能并不总是完全一致。拥有出色 Fiber 连接的用户并不一定拥有最佳 CPU 来解析和评估发送到其设备的 JavaScript。反之亦然 网络连接状况不佳,但 CPU 速度极快。— Kristofer Baxter,LinkedIn

我们可以看到,在低端和高端硬件上解析大约 1MB 解压缩(简单)JavaScript 的成本。对于市场上速度最快的手机与普通手机,解析/编译代码所用的时间相差 2-5 倍

ALT_TEXT_HERE
此图表突出显示了在不同类别的桌面设备和移动设备上,1MB 的 JavaScript 软件包(压缩后约为 250KB)的解析时间。在考虑解析成本时,需要考虑的是解压缩后的数字,例如,大约 250KB 的 gzip 压缩 JS 解压缩为大约 1MB 的代码。

像 CNN.com 这样的真实网站怎么样?

在高端 iPhone 8 上,只需大约 4 秒即可解析/编译 CNN 的 JS,而普通手机 (Moto G4) 只需大约 13 秒即可解析/编译。这会严重影响用户与此网站进行全面互动的速度。

ALT_TEXT_HERE
上图比较了 Apple 的 A11 Bionic 芯片的性能与普通 Android 硬件上的 Snapdragon 617 的性能。

这凸显了在普通硬件(例如 Moto G4)(而不仅仅是您口袋中的手机)上进行测试的重要性。但是,上下文很重要:根据用户的设备和网络条件进行优化

ALT_TEXT_HERE
Google Analytics(分析)可以深入分析真实用户访问您网站时使用的移动设备类。这样,您就有机会了解用户实际应对的 CPU/GPU 限制情况。

我们是否确实发送了过多的 JavaScript?呃,可能是 :)

使用 HTTP Archive(前 50 万个网站)来分析 JavaScript 在移动设备上的状态,我们可以看到,50% 的网站需要 14 秒以上才能进入可交互状态。这些网站只解析和编译 JS 就要花费最多 4 秒时间。

ALT_TEXT_HERE

考虑到提取和处理 JS 及其他资源所需的时间,用户可能会觉得页面需要等待一段时间可以使用,这也就不足为奇了。在这里我们肯定可以做得更好。

从网页中移除非关键 JavaScript 可以缩短传输时间、减少 CPU 密集型解析和编译以及潜在的内存开销。这也有助于加快网页的交互速度。

执行时间

这不仅仅是解析和编译,还需要付出一定的成本。JavaScript 执行(解析/编译后运行代码)是必须在主线程中执行的一种操作。较长的执行时间也可能会推迟用户与网站互动的时间。

ALT_TEXT_HERE

如果脚本执行时间超过 50 毫秒,可交互时间将因下载、编译和执行 JS 所需的整个时间而延迟 - Alex Russell

为了解决这个问题,可以将 JavaScript 分成多个小代码块,以避免锁定主线程。探索您能否减少执行期间完成的工作量。

其他费用

JavaScript 可通过其他方式影响网页性能:

  • 记忆。页面可能会因 GC(垃圾回收)而出现卡顿或频繁暂停的情况。当浏览器回收内存时,系统会暂停执行 JS,因此频繁收集垃圾的浏览器会导致暂停执行的频率超出我们的预期。请避免内存泄漏和频繁的 GCS 暂停,以确保页面不会卡顿。
  • 在运行时,长时间运行的 JavaScript 可能会阻塞主线程,从而导致页面无响应。将工作拆分成较小的片段(使用 requestAnimationFrame()requestIdleCallback() 进行调度)可以最大限度地减少响应速度问题,这有助于改进 Interaction to Next Paint (INP)

降低 JavaScript 交付费用的模式

当您尝试让 JavaScript 的解析/编译和网络传输时间保持较短的速度时,有一些模式可以帮助您,例如基于路由的分块或 PRPL

公共安全理事会 (PRPL)

PRPL(推送、渲染、预缓存、延迟加载)是一种通过积极的代码拆分和缓存来优化互动的模式:

ALT_TEXT_HERE

我们来直观了解它可能产生的影响。

我们使用 V8 的运行时调用统计信息来分析热门移动网站和渐进式 Web 应用的加载时间。如我们所见,许多网站将大部分时间都花在了解析时间(以橙色显示)中:

ALT_TEXT_HERE

Wego 是一个使用 PRPL 的网站,可设法保持较短的路由解析时间,从而快速进行交互。上述许多其他网站采用代码拆分和性能预算来尝试降低其 JS 费用。

渐进式引导

许多网站在提高内容曝光度的同时牺牲了与用户互动的代价。为了在确实有大型 JavaScript 软件包时快速进行首次绘制,开发者有时会采用服务器端渲染;然后进行“升级”,以便在最终提取 JavaScript 时附加事件处理脚本。

请小心,这会有自身的成本。您 1) 通常会发送较大的 HTML 响应,这可能会推动互动;2) 可能会让用户陷入神秘的山谷,在 JavaScript 处理完成之前,一半的体验实际上无法互动。

渐进式引导可能是更好的方法。发送具有最低限度功能的页面(仅包含当前路由所需的 HTML/JS/CSS)。 随着更多资源到达,应用可以延迟加载并解锁更多功能。

ALT_TEXT_HERE
渐进式引导,作者:Paul Lewis

加载与视图中的内容成比例的代码才是制胜之道。PRPL 和渐进式引导模式可以帮助您实现这一点。

总结

传输大小对于低端网络至关重要。对于受 CPU 限制的设备,解析时间非常重要。保持低水平至关重要。

多个团队已经成功采用严格的性能预算来保持较短的 JavaScript 传输和解析/编译时间。请参阅 Alex Russell 的“Can You Afford It?: 真实的网络性能预算”一文,以获得有关移动设备预算的指导。

ALT_TEXT_HERE
最好考虑一下我们做出的架构决策有多少 JS“余量”可供我们用于应用逻辑。

如果您要构建一个以移动设备为目标平台的网站,请尽可能在具有代表性的硬件上进行开发,保持较短的 JavaScript 解析/编译时间,并采用性能预算,以确保您的团队能够密切关注其 JavaScript 费用。

了解详情