优化启动性能

提高应用程序的启动性能通常是具有最高价值的性能优化之一。您的应用程序需要多长时间才能启动?在应用程序加载时,它是否会锁定设备或用户的浏览器?这会让用户担心您的应用程序已崩溃,或者其他地方出了问题。良好的用户体验包括确保您的应用程序能够快速加载。本文提供了有关编写新应用程序和将其他平台的应用程序移植到 Web 的性能技巧和建议。

快速异步加载

无论平台如何,尽快启动始终是一个好主意。既然这是一个普遍的问题,我们在这里不会过多关注它。相反,我们将关注构建 Web 应用程序时一个更重要的问题:尽可能地异步启动。这意味着不要在应用程序主线程的单个事件处理程序中运行所有启动代码。

相反,创建一个 Web Worker,该 Worker 在后台线程中尽可能多地完成工作(例如,获取和处理数据)。将任务分配给 Web Worker 可以将主线程释放出来处理需要它的任务,例如用户事件和渲染 UI。反过来,主线程事件应包含许多小任务,也称为 微任务,而不是更大、更耗时的任务。

异步加载有助于防止页面和用户界面看起来(或实际上成为)无响应。通过最小化任何单个加载任务所需的时间,应用程序的 事件循环将在启动时继续循环。这将防止应用程序、浏览器和/或设备看起来像是冻结了。

在最坏的情况下,阻塞主线程可能导致用户卸载您的应用程序;例如,如果有人错误地启动了您的应用程序,并且他们无法阻止关闭该应用程序,他们可能希望采取措施以防止这种情况再次发生。

有志者事竟成……

一开始就以“正确的方式”编写一切,比事后补救以提高性能(和可访问性)要容易得多。当您从头开始时,将适当的代码块异步化意味着无需事后补救。所有纯启动计算都应在后台线程中执行,同时保持主线程事件的运行时间尽可能短。不要包含进度指示器来告知用户正在发生什么以及他们需要等待多长时间,而是让进度条变得不必要。

另一方面,将现有应用程序移植到 Web 可能具有挑战性。原生应用程序不需要以异步方式编写,因为操作系统通常会为您处理加载。源应用程序可能有一个主循环,可以轻松地使其异步运行(通过单独运行每个主循环迭代);启动通常只是一个连续的、整体的过程,可能会定期更新进度计。

虽然您可以使用 Web Worker 来异步运行甚至非常大、耗时很长的 JavaScript 代码块,但有一个巨大的警告:Web Worker 不能直接操作 DOM,并且对 Window 对象的方法和属性的访问权限有限,包括无法访问 WebGL。所有这些都意味着,除非您可以轻松地将启动过程中的“纯计算”块提取到 worker 中,否则您最终将不得不在主线程上运行大部分或全部启动代码。

但是,即使是这样的代码,通过一些努力也可以使其异步。

实现异步

以下是一些关于如何使您的启动过程尽可能异步化的建议(无论是新应用程序还是移植应用程序)

  • 在 Web 应用程序所需的脚本标签上使用 deferasync 属性。这允许 HTML 解析器继续处理文档,而不必等到脚本下载并执行后才能继续。
  • 如果您需要解码资源文件(例如,解码 JPEG 文件并将其转换为原始纹理数据供 WebGL 后续使用),那么在 worker 中进行这项工作非常出色。
  • 在处理浏览器支持的数据时(例如,解码图像数据),请使用浏览器或设备内置的解码器,而不是自己编写或使用原始代码库中的解码器。提供的解码器几乎肯定会快得多,并且还可以减小您的应用程序大小。此外,浏览器可能会自动并行化这些解码器。
  • 任何可以并行处理的数据都应该并行处理。不要一次处理一块数据,而是在可能的情况下一次性处理所有数据!
  • 不要在启动 HTML 文件中包含不参与 关键渲染路径 的脚本或样式表。仅在需要时加载它们。
  • 减小 JavaScript 文件的大小。尝试将文件的最小化版本发送到浏览器,并使用 Gzip 或 Brotli 等压缩技术。
  • 尽可能利用资源提示(例如 preconnect 或 preload),向浏览器指示哪些文件对您的应用程序更关键。

您可以异步处理的事情越多,您的应用程序就能越好地利用多核处理器。

移植问题

一旦初始加载完成并且应用程序的主代码开始运行,您的应用程序可能必须是单线程的,特别是如果它是移植的。为帮助主代码的启动过程,最重要的事情是重构代码以分成小的片段。然后,这些片段可以在应用程序的主循环的多个调用之间穿插执行(这样主线程就可以处理输入等)。

Emscripten 提供了一个 API 来帮助进行这种重构;例如,您可以使用 emscripten_push_main_loop_blocker() 来建立一个在主线程继续执行之前执行的函数。通过建立一个要按顺序调用的函数队列,您可以更轻松地管理代码片段的执行,而不会阻塞主线程。

然而,这仍然存在必须重构现有代码以实际按此方式工作的难题。这可能需要一些时间。

我应该有多异步?

您的网站首次变得可用并且对用户输入的响应越快,它的感知就会越好。通常认为需要 1 到 2 秒才能显示内容的网站是快速的;如果您习惯了需要 3 到 4 秒的网站,那么 7 到 8 秒就会感觉很长。

在响应能力方面,用户不会注意到 50ms 或更短的延迟。任何超过 200ms 的延迟,用户都会觉得您的网站反应迟钝。在改进应用程序的加载和响应能力时,请记住,您的许多用户可能拥有比您更旧、更慢的计算机,他们可能会遇到比您更长的延迟!

其他建议

除了异步化之外,还有其他方法可以帮助您提高应用程序的启动时间。以下是其中一些:

下载时间

请记住用户下载应用程序数据所需的时间。如果您的应用程序非常受欢迎,或者需要频繁重新下载内容,您应该尽量拥有尽可能快的托管服务器。始终 压缩您的数据,使其尽可能小。

数据大小

尽最大努力优化数据大小;较小的关卡文件将比较大的文件下载和处理得更快。

主观因素

您可以做的任何有助于在启动过程中让用户保持参与的事情,都可以帮助缩短感觉上的时间。显示模拟的启动屏幕可以提高 感知性能。对于大型网站,任何可以帮助用户感觉您的应用程序正在执行某些操作而不是静默等待的事情都有帮助。

另见