Async Wasm
28.1 The Problem
C/C++/Rust code is often synchronous (blocking file reads, sleep, synchronous network calls), but browsers expose asynchronous APIs (Promises). Wasm execution can't block the main thread.
28.2 Asyncify (Binaryen/Emscripten)
A compile-time transform that lets Wasm code unwind and rewind its stack, so it can pause while JS awaits a Promise, then resume.
Costs: larger code and slower execution (instrumentation). Limit it with -sASYNCIFY_ONLY / ASYNCIFY_IMPORTS.
#include <emscripten.h>
EM_ASYNC_JS(int, fetch_length, (const char* url), {
const res = await fetch(UTF8ToString(url));
return (await res.text()).length;
});
int main() {
int len = fetch_length("/data.txt"); // looks synchronous in C
emscripten_sleep(100); // also uses Asyncify
return len;
}emcc app.c -O3 -sASYNCIFY -o app.js28.3 JS Promise Integration (JSPI)
A standardized engine feature (in Chrome 137+, other browsers following): wrap Wasm exports with WebAssembly.promising and imports with WebAssembly.Suspending. Wasm suspends on a Promise without code transformation.
Emscripten: -sJSPI. Much smaller and faster than Asyncify.
const suspendingFetch = new WebAssembly.Suspending(async (ptr, len) => {
const res = await fetch(readString(ptr, len));
return (await res.arrayBuffer()).byteLength;
});
const { instance } = await WebAssembly.instantiate(bytes, { env: { fetch_len: suspendingFetch } });
const run = WebAssembly.promising(instance.exports.run);
const result = await run(); // returns a Promise