6

我正在尝试一个简单的 hello world WebAssembly 示例,但无法理解我在 Chrome 59 中看到的错误:

RangeError:如果缓冲区大小大于 4KB,则主线程上不允许 WebAssembly.Compile。使用 WebAssembly.compile,或在工作线程上编译。

src/wasm/counter.wasm:13
  10 | let wa;
  11 | const make = source => {
  12 |   // buffer should already be set
> 13 |   return wa = new Module(buffer);
  14 | };
  15 | 
  16 | const WebAssemblyModule = function(deps = {

我已按照本教程中的步骤进行操作,并且可以毫无错误地构建所有内容。我正在使用create-react-app 重新接线wasm-loader

如果我使用的是计数器模块的本地版本,则会收到我在开头提到的错误。如果我尝试使用预构建的版本(例如这个项目中的那个),它可以正常工作。

当我构建我的模块时,我使用的命令与教程中指定的相同。具有工作模块的项目在其 README 中列出了相同的命令:

emcc counter.c -O1 -o counter.wasm -s WASM=1 -s SIDE_MODULE=1

知道可能导致错误的原因吗?

4

2 回答 2

4

一些浏览器限制了可以同步编译的模块的大小,因为这会阻塞主线程。正如错误消息所说,他们宁愿让你使用WebAssembly.compilewhich 返回一个promise. 我建议您更进一步并使用WebAssembly.instantiate它将异步编译和实例化,并且在某些情况下生成更高性能的代码。查看它的文档,签名是:

Promise<WebAssemblyInstantiatedSource>
  instantiate(BufferSource bytes [, importObject])

bytes是您传递给Module上面的同一个缓冲区,并且importObject是您传递给的同一个缓冲区Instance


另一种选择是使您的.wasm文件更小。这很脆弱,因为主线程大小限制是任意的,而且您并不能真正控制生成代码的大小。您可以尝试使用-O2or进行编译-Os,并且可以运行binaryen的优化器来尝试减小大小。您还可以将代码拆分为多个较小的模块,分别编译每个模块,然后将它们动态链接在一起(共享导入/导出,并为所有模块使用相同的内存)。

但同样,这并不是你真正应该依赖的东西,而且你仍然阻塞了主线程。


另一种选择是将所有代码移动到WebWorker。您可以根据需要尽可能多地阻止它们,不需要Promises。

于 2017-07-24T15:55:50.573 回答
0

通过 Buffer 创建一个 URL 对象,然后使用 instantiateStreaming 异步方法加载 wasm。

const blob = new Blob([buffer], { type: "application/wasm" });
const url = URL.createObjectURL(blob);
wasm = await instantiateStreaming(fetch(url), {});
于 2019-04-23T14:39:30.273 回答