examples/jspi-fetch-streams/index.html
JSPI lets plain (non-async) Rust suspend a WASM fiber while awaiting a JS Promise — without blocking the event loop. This example applies that to the Streams API: each reader.read() Promise suspends the fiber until the next chunk arrives.
WebAssembly.SuspendingResponse streamingRequest body streamingWASM module
drain_stream is a plain Rust helper (no async, no .await) that loops calling block_on_promise(&reader.read()), suspending the JSPI fiber on each chunk:
fndrain\_stream(stream: ReadableStream) -> Result<(u32, u32), JsValue> {letreader: ReadableStreamDefaultReader = stream.get\_reader().unchecked\_into();let(muttotal,mutchunks) = (0u32, 0u32);loop{// Suspends the JSPI fiber until the next chunk (or done) resolves.letresult: ReadableStreamReadResult =block\_on\_promise(&reader.read())?.unchecked\_into();ifresult.get\_done().unwrap\_or(true) {break; }letchunk: Uint8Array = result.get\_value().unchecked\_into();
total += chunk.length();
chunks += 1;
}Ok((total, chunks))
}
This helper powers two exports:
| export | description | browser support |
|---|---|---|
read_stream(stream) | reads any ReadableStream from Rust — request body, synthetic stream, etc. | Chrome, Firefox, Safari |
fetch_stream(url) | fetches url and streams the response body | Chrome, Firefox, Safari |
Sending a ReadableStream as a fetch request body requires duplex: "half" on the RequestInit. Firefox and Safari do not support this; they throw a TypeError when a ReadableStream is used as the request body.
Detection pattern (works in all browsers without throwing):
letsupported =false;try{newRequest('', {
body:newReadableStream(),
method:'POST',getduplex() { supported =true;return'half'; },
});
}catch{}// supported === true ⟹ Chrome/Chromium// supported === false ⟹ Firefox / Safari
On the Service Worker / server side (Rust receiving the request), the fallback is to buffer the body via arrayBuffer() when request.body is null (Firefox), and to use ReadableStream chunk-by-chunk via block_on_promise when it is present (Chrome).
① Fetch + stream response② Read a ReadableStream③ Request streaming support?④ Concurrent fibers▶ Run all
clear