加载和运行 WebAssembly 代码
要在 JavaScript 中使用 WebAssembly,您首先需要在编译/实例化之前将模块加载到内存中。本文提供了有关可用于获取 WebAssembly 字节码的不同机制的参考,以及如何编译/实例化然后运行它的参考。
有哪些选项?
WebAssembly 尚未与<script type='module'>
或import
语句集成,因此没有路径可以让浏览器使用导入为您获取模块。
较旧的WebAssembly.compile
/WebAssembly.instantiate
方法要求您在获取原始字节后创建一个包含 WebAssembly 模块二进制文件的ArrayBuffer
,然后编译/实例化它。这类似于new Function(string)
,除了我们用字节数组缓冲区(WebAssembly 源代码)替换字符字符串(JavaScript 源代码)。
较新的WebAssembly.compileStreaming
/WebAssembly.instantiateStreaming
方法效率更高——它们直接对来自网络的原始字节流执行操作,无需ArrayBuffer
步骤。
那么我们如何将这些字节放入数组缓冲区并进行编译呢?以下部分将进行说明。
使用 Fetch
Fetch是一个方便的现代 API,用于获取网络资源。
获取 Wasm 模块最快、最有效的方法是使用较新的WebAssembly.instantiateStreaming()
方法,该方法可以将fetch()
调用作为其第一个参数,并且将一步完成获取、编译和实例化模块的操作,在模块从服务器流式传输时访问原始字节码
WebAssembly.instantiateStreaming(fetch("simple.wasm"), importObject).then(
(results) => {
// Do something with the results!
},
);
如果我们使用较旧的WebAssembly.instantiate()
方法(它不适用于直接流),我们需要额外的一步将获取的字节码转换为ArrayBuffer
,如下所示
fetch("module.wasm")
.then((response) => response.arrayBuffer())
.then((bytes) => WebAssembly.instantiate(bytes, importObject))
.then((results) => {
// Do something with the results!
});
关于 instantiate() 重载
WebAssembly.instantiate()
函数有两种重载形式——上面显示的形式将要编译的字节码作为参数,并返回一个 Promise,该 Promise 解析为一个包含编译后的模块对象及其实例化实例的对象。该对象如下所示
{
module: Module, // The newly compiled WebAssembly.Module object,
instance: Instance, // A new WebAssembly.Instance of the module object
}
注意:通常我们只关心实例,但如果我们想要缓存它、通过postMessage()
与其他工作线程或窗口共享它,或者创建更多实例,则拥有模块很有用。
注意:第二种重载形式将WebAssembly.Module
对象作为参数,并直接返回一个包含实例对象作为结果的 Promise。请参阅第二个重载示例。
运行您的 WebAssembly 代码
一旦您在 JavaScript 中获得了 WebAssembly 实例,您就可以开始使用通过WebAssembly.Instance.exports
属性导出的其功能。您的代码可能如下所示
WebAssembly.instantiateStreaming(fetch("myModule.wasm"), importObject).then(
(obj) => {
// Call an exported function:
obj.instance.exports.exported_func();
// or access the buffer contents of an exported memory:
const dv = new DataView(obj.instance.exports.memory.buffer);
// or access the elements of an exported table:
const table = obj.instance.exports.table;
console.log(table.get(0)());
},
);
注意:有关 WebAssembly 模块导出工作原理的更多信息,请阅读使用 WebAssembly JavaScript API和了解 WebAssembly 文本格式。
使用 XMLHttpRequest
XMLHttpRequest
比 Fetch 略旧,但仍然可以愉快地用于获取类型化数组。同样,假设我们的模块称为simple.wasm
- 创建一个新的
XMLHttpRequest()
实例,并使用其open()
方法打开请求,将请求方法设置为GET
,并声明我们要获取的文件的路径。 - 这部分的关键是使用
responseType
属性将响应类型设置为'arraybuffer'
。 - 接下来,使用
XMLHttpRequest.send()
发送请求。 - 然后,我们使用
load
事件处理程序在响应完成下载时调用一个函数——在这个函数中,我们从response
属性获取数组缓冲区,然后将其馈送到我们的WebAssembly.instantiate()
方法中,就像我们使用 Fetch 时一样。
最终代码如下所示
const request = new XMLHttpRequest();
request.open("GET", "simple.wasm");
request.responseType = "arraybuffer";
request.send();
request.onload = () => {
const bytes = request.response;
WebAssembly.instantiate(bytes, importObject).then((results) => {
results.instance.exports.exported_func();
});
};
注意:您可以在xhr-wasm.html中看到此示例。