asm.js 的异步脚本

每个中型或大型游戏都应该将 asm.js 代码作为异步脚本的一部分进行编译,以赋予浏览器优化编译过程的最大灵活性。在 Gecko 中,异步编译允许 JavaScript 引擎在游戏加载时在主线程之外编译 asm.js,并缓存生成的机器代码,以便在后续加载时无需重新编译(自 Firefox 28 起)。要查看区别,请在 about:config 中切换 javascript.options.parallel_parsing

让异步发挥作用

实现异步编译非常简单:在编写 JavaScript 时,只需像这样使用 async 属性

html
<script async src="file.js"></script>

或者,通过脚本实现相同的功能

js
const script = document.createElement("script");
script.src = "file.js";
document.body.appendChild(script);

(通过脚本创建的脚本默认设置为 async。)Emscripten 生成的默认 HTML shell 会产生后者。

何时异步不是异步?

根据 HTML 规范的定义,以下两种情况脚本不是异步的:

html
<script async>
  // Inline JavaScript code
</script>

and

js
const script = document.createElement("script");
script.textContent = "// Inline JavaScript code";
document.body.appendChild(script);

这两种情况都被视为“内联”脚本,会立即进行编译和运行。

如果您的代码在 JS 字符串中怎么办?请使用 Blob 和对象 URL,而不是使用 evalinnerHTML,因为这两者都会触发同步编译:

js
const blob = new Blob([codeString]);
const script = document.createElement("script");
const url = URL.createObjectURL(blob);
script.onload = script.onerror = () => URL.revokeObjectURL(url);
script.src = url;
document.body.appendChild(script);

通过设置 src 属性而不是使用 innerHTML,使得该脚本是异步的。