WebAssembly.Compile 在主线程上是不允许的,如果缓冲区大小大于 4KB
WebAssembly.Compile is disallowed on the main thread, if the buffer size is larger than 4KB
我正在尝试一个简单的 hello world WebAssembly 示例,但我无法理解我在 Chrome 59:
中看到的错误
RangeError: WebAssembly.Compile is disallowed on the main thread, if the buffer size is larger than 4KB. Use WebAssembly.compile, or compile on a worker thread.
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, and I can build everything without error. I'm using create-react-app
rewired with wasm-loader
中的步骤操作。
如果我使用本地构建的计数器模块,我会收到开头提到的错误。如果我尝试使用预构建版本(例如in this project),它工作正常。
当我构建我的模块时,我使用的是教程中指定的相同命令。具有工作模块的项目在其自述文件中列出了相同的命令:
emcc counter.c -O1 -o counter.wasm -s WASM=1 -s SIDE_MODULE=1
知道可能导致错误的原因吗?
一些浏览器限制了可以同步编译的模块的大小,因为这会阻塞主线程。正如错误消息所说,他们宁愿让你使用 WebAssembly.compile
which returns a promise
. I'd advise you to go further and use WebAssembly.instantiate
which will both compile and instantiate asynchronously and, in some cases, generate higher performance code. See its documentation,签名是:
Promise<WebAssemblyInstantiatedSource>
instantiate(BufferSource bytes [, importObject])
bytes
与您在上面传递给 Module
的缓冲区相同,而 importObject
与您传递给 Instance
.[=25 的缓冲区相同=]
另一种选择是缩小 .wasm
文件。这非常脆弱,因为主线程大小限制是任意的,您无法真正控制生成代码的大小。您可以尝试使用 -O2
或 -Os
进行编译,并且您可以使用 运行 binaryen 的优化器来尝试减小大小。您还可以将代码拆分为多个较小的模块,分别编译每个模块,然后动态 link 将它们组合在一起(共享导入/导出,并为所有模块使用相同的内存)。
但同样,这并不是您真正应该依赖的东西,而且您仍在阻塞主线程。
另一种选择是将所有代码移动到 WebWorker。您可以根据需要阻止它们,不需要 Promise
s.
通过Buffer创建一个URL对象,然后使用instantiateStreaming异步方法加载wasm。
const blob = new Blob([buffer], { type: "application/wasm" });
const url = URL.createObjectURL(blob);
wasm = await instantiateStreaming(fetch(url), {});
我正在尝试一个简单的 hello world WebAssembly 示例,但我无法理解我在 Chrome 59:
中看到的错误RangeError: WebAssembly.Compile is disallowed on the main thread, if the buffer size is larger than 4KB. Use WebAssembly.compile, or compile on a worker thread.
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, and I can build everything without error. I'm using create-react-app
rewired with wasm-loader
中的步骤操作。
如果我使用本地构建的计数器模块,我会收到开头提到的错误。如果我尝试使用预构建版本(例如in this project),它工作正常。
当我构建我的模块时,我使用的是教程中指定的相同命令。具有工作模块的项目在其自述文件中列出了相同的命令:
emcc counter.c -O1 -o counter.wasm -s WASM=1 -s SIDE_MODULE=1
知道可能导致错误的原因吗?
一些浏览器限制了可以同步编译的模块的大小,因为这会阻塞主线程。正如错误消息所说,他们宁愿让你使用 WebAssembly.compile
which returns a promise
. I'd advise you to go further and use WebAssembly.instantiate
which will both compile and instantiate asynchronously and, in some cases, generate higher performance code. See its documentation,签名是:
Promise<WebAssemblyInstantiatedSource>
instantiate(BufferSource bytes [, importObject])
bytes
与您在上面传递给 Module
的缓冲区相同,而 importObject
与您传递给 Instance
.[=25 的缓冲区相同=]
另一种选择是缩小 .wasm
文件。这非常脆弱,因为主线程大小限制是任意的,您无法真正控制生成代码的大小。您可以尝试使用 -O2
或 -Os
进行编译,并且您可以使用 运行 binaryen 的优化器来尝试减小大小。您还可以将代码拆分为多个较小的模块,分别编译每个模块,然后动态 link 将它们组合在一起(共享导入/导出,并为所有模块使用相同的内存)。
但同样,这并不是您真正应该依赖的东西,而且您仍在阻塞主线程。
另一种选择是将所有代码移动到 WebWorker。您可以根据需要阻止它们,不需要 Promise
s.
通过Buffer创建一个URL对象,然后使用instantiateStreaming异步方法加载wasm。
const blob = new Blob([buffer], { type: "application/wasm" });
const url = URL.createObjectURL(blob);
wasm = await instantiateStreaming(fetch(url), {});