得鹿梦鱼 得鹿梦鱼

优化启动性能

更好地启动

不论在什么平台上,尽可能快地启动总是一个好主意。因为这是个很宽泛的问题,在这里我们不会着重关注。相反我们会关注构建 Web 应用时更重要的一个问题:尽可能异步地启动。这意味着不要将你所有的启动代码在应用主线程中的唯一一个事件处理函数中运行。

相反,你应该这样写你的代码,让你的应用在后台线程创建一个 Web worker ,做尽可能多的工作(比如,获取和处理数据)。然后,所有必须在主线程中完成的事情(比如用户事件和渲染用户界面)应该被分成小的片段,这样,当应用启动时,应用的事件循环就可以持续地运行下去。这可以避免应用、浏览器以及/或者设备出现锁死。

如果打算重构

如果你从头开始你的项目,通常很容易把所有的东西都写成“正确的方式”,使得代码片段具有合适的异步性。所有纯粹在启动时的计算应该在后台线程中执行,同时使主线程事件的运行时间尽可能缩短。应包含进度指示器,以便用户知道发生了什么以及他们将要等待多久。从理论上来说,无论如何,设计新的应用程序并能很好地启动应该很容易。

但是,另一方面,当你将现有应用程序移植到 Web 上时,问题会变得棘手。桌面应用程序不需要以异步方式编写,因为通常操作系统会为你处理该问题;或者应用程序当前是唯一正在运行的主要任务,而这具体取决于操作环境。源程序可能有一个主循环,可以被轻松地改成异步操作(通过分别运行每个主循环);启动通常只是一个持续的整体过程,过程中可能会定期更新进度表。

虽然你可以使用 Web workers 异步运行体积巨大,持续时间长的 JavaScript 代码块,但还是要给出一个重大警告:workers 不具备访问 WebGL 或音频的能力,亦不能向主线程发送同步消息,所以你甚至不能将这些 API 代理到主线程中。所有的这一切意味着,除非你够轻松地抽取启动过程中的“纯计算”代码块,加入到 workers 中,否则你最后还是得在主线程上运行大部分或全部的启动代码。

异步化

  • 启动时,在需要异步执行的脚本标签上使用 defer 或 async 属性。这会允许 HTML 解析器更高效地处理文档
  • 如果你需要解码资源文件(比如,解码 JPEG 文件并将其转换为原始纹理数据,以便随后在 WebGL 中使用),最好在 workers 里做这件事。
  • 当处理浏览器支持的数据格式时(例如,解析图像数据),使用设备或浏览器内置的解码器而不是运行你自己的或者使用 or using one from the original codebase。预先提供的那个基本上一定会快得多,并且能够减小你的应用的启动体积。另外,浏览器可以自动并行化这些解码器的工作。
  • 所有能并行的数据处理都应该并行化。不要一团接一团地处理数据,如果可能的话,同时处理它们!
  • 在你启动的HTML文件中,不要包含不会在关键路径下出现的脚本或样式表。只在需要时加载他们
  • 不要强迫 Web 引擎构建不需要的 DOM,一种简单的“hack”的方式是把你的 HTML 留在文档里,但是在外层包裹注释,如下
<div id="foo">  <!--    <div> ...  --></div>
// 当文档的一部分需要被渲染时,加载被注释的 HTMLfoo.innerHTML = foo.firstChild.nodeValue;

其他

  1. 下载时间:使用托管服务器,压缩数据
  2. GPU 因素
  3. 数据大小
  4. 主观因素:在启动过程中做一些事情来使用户专注于其上,这会让时间看起来过得更快些