如果缓冲区大小大于 4KB,则主线程上不允许使用 WebAssembly.Compile

Ale*_*ian 8 javascript webassembly

我正在尝试一个简单的 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 = {
Run Code Online (Sandbox Code Playgroud)

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

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

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

emcc counter.c -O1 -o counter.wasm -s WASM=1 -s SIDE_MODULE=1
Run Code Online (Sandbox Code Playgroud)

知道什么可能导致错误吗?

JF *_*ien 6

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

Promise<WebAssemblyInstantiatedSource>
  instantiate(BufferSource bytes [, importObject])
Run Code Online (Sandbox Code Playgroud)

bytes与您传递给上面的缓冲区相同Module,并且importObject与您传递给 的缓冲区相同Instance


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

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


另一种选择是将所有代码移至WebWorker。您可以根据需要阻止它们,无需Promises。