JavaScript 启动优化

随着我们构建的网站越来越依赖 JavaScript,我们有时会为我们发送的内容付出代价,而这些代价并非总是容易看到。在本文中,我们将介绍如果您希望您的网站在移动设备上快速加载并具有交互性,那么一点规范为何会有所帮助。减少 JavaScript 的交付量意味着减少网络传输时间,减少代码解压缩所花费的时间,以及减少解析和编译此 JavaScript 所花费的时间。

网络

当大多数开发人员考虑 JavaScript 的成本时,他们会从下载和执行成本的角度来考虑。通过线路发送更多字节的 JavaScript,用户的连接速度越慢,所需时间就越长。

When a browser requests a
resource, that resource needs to be fetched and then decompressed. In the case
of resources like JavaScript, they must be parsed and compiled prior to
execution.

这可能是一个问题,因为用户拥有的有效网络连接类型实际上可能不是 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 DevTools 中,解析和编译是 Performance 面板中黄色“脚本”时间的一部分。

ALT_TEXT_HERE

“自下而上”和“调用树”选项卡会显示确切的解析/编译时间

ALT_TEXT_HERE
Chrome DevTools Performance 面板 > 自下而上。启用 V8 的运行时调用统计信息后,我们可以看到在解析和编译等阶段花费的时间

但是,这有什么关系呢?

ALT_TEXT_HERE

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

按字节计算,对于浏览器来说,处理 JavaScript 比处理同等大小的图像或 Web 字体更昂贵 — 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 仿生芯片与更普通的 Android 硬件中的 Snapdragon 617 性能的解析时间。

这突出了在普通硬件(如 Moto G4)上进行测试的重要性,而不仅仅是在您口袋里的手机上进行测试。然而,上下文很重要:针对您的用户拥有的设备和网络条件进行优化。

ALT_TEXT_HERE
Google Analytics 可以提供有关您的真实用户访问您的网站所使用的 移动设备类别 的见解。这可以提供机会来了解他们正在使用的真实 CPU/GPU 约束。

我们真的发送了太多 JavaScript 吗?嗯,可能吧 :)

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

ALT_TEXT_HERE

考虑到获取和处理 JS 和其他资源所需的时间,用户在感觉页面可以使用之前可能需要等待一段时间也就不足为奇了。我们绝对可以在这方面做得更好。

从您的页面中删除非关键 JavaScript 可以减少传输时间、CPU 密集型解析和编译以及潜在的内存开销。这也有助于更快地使您的页面具有交互性。

执行时间

不仅仅是解析和编译会产生成本。JavaScript 执行(解析/编译代码后运行代码)是在主线程上必须执行的操作之一。长时间的执行时间也会推迟用户与您的网站进行交互的时间。

ALT_TEXT_HERE

如果脚本执行时间超过 50 毫秒,则交互时间将被下载、编译和执行 JS 所需的全部时间延迟 — Alex Russell

为了解决这个问题,JavaScript 受益于分成小块,以避免锁定主线程。探索是否可以减少执行期间完成的工作量。

其他成本

JavaScript 可能会以其他方式影响页面性能

  • 内存。由于 GC(垃圾回收),页面可能会频繁出现卡顿或暂停。当浏览器回收内存时,JS 执行会暂停,因此频繁收集垃圾的浏览器可能会比我们希望的更频繁地暂停执行。避免 内存泄漏 和频繁的 GC 暂停,以保持页面流畅。
  • 在运行时,长时间运行的 JavaScript 可能会阻塞主线程,导致页面无响应。将工作分解成更小的块(使用 requestAnimationFrame()requestIdleCallback() 进行调度)可以最大限度地减少响应性问题,这可以帮助改进 交互到下次绘制 (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 的“您能负担得起吗?:真实世界的 Web 性能预算”,以获取有关移动设备预算的指导。

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

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

了解更多