我正在尝试一个简单的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
知道可能导致错误的原因是什么?
答案 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), {});