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

时间:2017-07-24 15:41:31

标签: 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 = {

我已经按照this tutorial中的步骤操作了,我可以毫无错误地构建所有内容。我正在使用create-react-app rewired with wasm-loader

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

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

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

知道可能导致错误的原因是什么?

2 个答案:

答案 0 :(得分:2)

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

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

bytes与上面传递给Module的缓冲区相同,importObject与您传递给Instance的内容相同。

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

但同样,这不是你应该依赖的东西,你仍然在阻止主线程。

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

答案 1 :(得分:0)

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

const blob = new Blob([buffer], { type: "application/wasm" });
const url = URL.createObjectURL(blob);
wasm = await instantiateStreaming(fetch(url), {});