JavaScript 启动优化

随着我们构建的网站越来越依赖 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,请参阅文件名哈希。

解析/编译

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

ALT_TEXT_HERE

“自下而上”和“调用树”标签页会显示确切的解析/编译时间:

ALT_TEXT_HERE
Chrome 开发者工具的“性能”面板 >“自下而上”。启用 V8 的运行时调用统计信息后,我们可以查看在解析和编译等阶段花费的时间

但为什么这很重要?

ALT_TEXT_HERE

花费很长时间解析/编译代码可能会严重延迟用户与网站互动的时间。您发送的 JavaScript 越多,在网站可供互动之前解析和编译 JavaScript 所需的时间就越长。

对于浏览器而言,处理 JavaScript 的开销要高于处理大小相同的图片或网页字体 - Tom Dale

与 JavaScript 相比,处理大小相当的图片会产生大量费用(它们仍需解码!),但在普通移动硬件上,JS 更有可能对网页的可交互性产生负面影响。

ALT_TEXT_HERE
JavaScript 和图片字节的开销大不相同。图片在解码和光栅化时通常不会阻塞主线程或阻止界面进行互动。不过,JS 可能会因解析、编译和执行开销而延迟互动。

当我们说解析和编译速度慢时,背景信息很重要,我们这里说的是普通手机。普通用户的手机可能配备速度较慢的 CPU 和 GPU,没有 L2/L3 缓存,甚至可能存在内存限制。

网络功能和设备功能并不总是匹配。即使拥有出色的光纤连接,用户也不一定拥有最好的 CPU 来解析和评估发送到其设备的 JavaScript。反之亦然,网络连接很差,但 CPU 速度极快。— Kristofer Baxter,LinkedIn

下面,我们可以看到在低端和高端硬件上解析约 1MB 解压缩(简单)JavaScript 的费用。在市场上运行速度最快的手机和普通手机之间,解析/编译代码所需的时间相差 2 到 5 倍。

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

如果是真实网站(例如 CNN.com),情况会怎样?

在高端 iPhone 8 上,解析/编译 CNN 的 JS 仅需约 4 秒,而在普通手机 (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 执行会暂停,因此频繁收集垃圾的浏览器可能会比我们希望的更频繁地暂停执行。避免内存泄漏和频繁的 GC 暂停,以使网页保持流畅。
  • 在运行时,长时间运行的 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?: Real-world Web Performance Budgets”(真实世界 Web 性能预算),了解有关移动设备预算的指导。

ALT_TEXT_HERE
考虑我们做出的架构决策可以为应用逻辑留出多少 JS“余量”很有用。

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

了解详情