WebAssembly.instantiate()

Baseline Widely available *

This feature is well established and works across many devices and browser versions. It’s been available across browsers since October 2017.

* Some parts of this feature may have varying levels of support.

WebAssembly.instantiate() 静态方法允许你编译和实例化 WebAssembly 代码。它有两个重载方式:

  • 主重载方式使用类型化数组ArrayBuffer 格式的 WebAssembly 二进制代码,并在一个步骤中执行编译和实例化。返回的 Promise 将兑现为已编译的 WebAssembly.Module 和该模块的第一个 WebAssembly.Instance
  • 次重载方式使用已编译的 WebAssembly.Module, 返回的 Promise 将兑现为该 ModuleInstance。当 Module 已经被编译时这种方式较为有用。

警告: 此方法不是获取和实例化 Wasm 模块的最高效的方法。如果可能的话,你应该改用较新的 WebAssembly.instantiateStreaming() 方法,该方法在一个步骤中直接从原始字节码获取、编译和实例化模块,因此不需要转换为 ArrayBuffer

语法

js
// 使用 Wasm 二进制代码
WebAssembly.instantiate(bufferSource)
WebAssembly.instantiate(bufferSource, importObject)
WebAssembly.instantiate(bufferSource, importObject, compileOptions)

// 使用模块对象实例
WebAssembly.instantiate(module)
WebAssembly.instantiate(module, importObject)
WebAssembly.instantiate(module, importObject, compileOptions)

参数

bufferSource

包含你想编译的 Wasm 模块的二进制代码的类型化数组ArrayBuffer

module

要实例化的 WebAssembly.Module 对象。

importObject 可选

包含要导入到新创建的 Instance 的值(例如,函数或 WebAssembly.Memory 对象)的对象。已编译的模块中每个声明的导入应有一个匹配的属性,否则将抛出 WebAssembly.LinkError

compileOptions 可选

包含编译选项的对象。属性包含:

builtins 可选

由用于在已编译的 Wasm 模块中启用 JavaScript 内置用法的字符串组成的数组。字符串定义的是你所希望启用的内置。当前唯一可用的值是 "js-string",其将启用 JavaScript 字符串内置。

importedStringConstants 可选

指定导入的全局字符串常量命名空间的字符串。当你希望在 Wasm 模块中使用导入的全局字符串时需要指定该属性。

返回值

如果传递的是 bufferSource,返回的 Promise 将兑现为包含两个字段的 ResultObject

如果传递的是 module,返回的 Promise 将兑现为 WebAssembly.Instance 对象。

异常

示例

备注: 在大多数情况下,你可能想要使用 WebAssembly.instantiateStreaming(),因为它比 instantiate() 更高效。

第一种重载示例

使用 fetch 获取一些 WebAssembly 字节码后,我们使用 WebAssembly.instantiate() 函数编译并实例化模块,在此过程中,将一个 JavaScript 函数导入到 WebAssembly 模块中,接下来我们调用 Instance导出的 WebAssembly 函数

js
const importObject = {
  my_namespace: {
    imported_func(arg) {
      console.log(arg);
    },
  },
};

fetch("simple.wasm")
  .then((response) => response.arrayBuffer())
  .then((bytes) => WebAssembly.instantiate(bytes, importObject))
  .then((result) => result.instance.exports.exported_func());

备注: 你也可以在 GitHub 上的 index.html 中找到这个示例(也可以在线查看)。

第二种重载示例

下面的例子(在 GitHub 上查看我们的 index-compile.html 示例,也可在线查看)使用 WebAssembly.compileStreaming() 方法编译已加载的 simple.wasm 字节码,然后使用 postMessage() 将其发送到 worker

js
const worker = new Worker("wasm_worker.js");

WebAssembly.compileStreaming(fetch("simple.wasm")).then((mod) =>
  worker.postMessage(mod),
);

在 worker 中(查看 wasm_worker.js),我们定义一个模块要用的导入对象,然后设置一个用于从主线程接收模块的事件处理器。当接收到模块后,我们使用 WebAssembly.instantiate() 方法创建一个实例并调用从它的内部导出的函数。

js
const importObject = {
  my_namespace: {
    imported_func(arg) {
      console.log(arg);
    },
  },
};

onmessage = (e) => {
  console.log("从主线程接收到的模块");
  const mod = e.data;

  WebAssembly.instantiate(mod, importObject).then((instance) => {
    instance.exports.exported_func();
  });
};

启用 JavaScript 内置和全局字符串导入

这个示例在用 instantiate() 编译和实例化 Wasm 模块时,启用 JavaScript 字符串内置和导入的全局字符串常量,然后运行导出的 main() 函数(输出 "hello world!" 到控制台)。查看在线示例

js
const importObject = {
  // 常规导入
  m: {
    log: console.log,
  },
};

const compileOptions = {
  builtins: ["js-string"], // 启用 JavaScript 字符串内置
  importedStringConstants: "string_constants", // 启用导入的全局字符串常量
};

fetch("log-concat.wasm")
  .then((response) => response.arrayBuffer())
  .then((bytes) => WebAssembly.instantiate(bytes, importObject, compileOptions))
  .then((result) => result.instance.exports.main());

规范

Specification
WebAssembly JavaScript Interface
# dom-webassembly-instantiate

浏览器兼容性

参见