emscripten:在 Node.js 中异步调用时,C 函数不是 "ready"

emscripten: C functions not "ready" when called asynchronously in Node.js

我用 Emscripten 编译了一个 C 库,并编写了可以在交互式 Node.js shell:

中正确交互的 JS
// script compiled by Emscripten
const _smaz = require("./_smaz");
var out_heap = _smaz['_malloc'](encoded.length * 8);
...

但是,当在我的应用程序中立即调用该函数时,_malloc 失败:

TypeError: Cannot read property 'apply' of undefined
    at Object.a._malloc

即使添加 100 毫秒 setTimeout 也可以解决问题。看起来编译后的 Emscripten 东西是异步加载的,函数不能立即使用。

正确的处理方法是什么? Emscripten docs 建议在我的 "page" 加载后添加一个 Module['onRuntimeInitialized'] 函数,但我不确定它应该在服务器端 Node.js 应用程序中的什么位置或者它是否完全适用。

以下是我的编译方式:

emcc smaz.c -O2 -o _smaz.js --closure 1 -s EXPORTED_FUNCTIONS="['_smaz_compress', '_smaz_decompress']" -s 'EXTRA_EXPORTED_RUNTIME_METHODS=["ccall", "cwrap"]'

原来有两个 emcc 编译器选项可以禁用异步 startup/loading 行为:-s BINARYEN_ASYNC_COMPILATION=0-s SINGLE_FILE=1。这解决了我的问题。

来自相关GitHub issue:

In general emscripten tries to do startup asynchronously for wasm, because it's what browsers can best optimize, and worse, Chrome currently has a limitation on the size of synchronous compilations (hopefully will be fixed soon). But you can force sync compilation with -s BINARYEN_ASYNC_COMPILATION=0.

That still leaves fetching the wasm binary file. By default we fetch it asynchronously, but if you have a way to get it yourself before, you can set it on Module['wasmBinary'] and we will just use that synchronously. Alternatively, #5296 will add an option to embed that file, making it available synchronously.