写过三年 Rust Wasm,今天才发现它的异步生态从来没真正 ready 过——Wasmtime 46 把这件事从根上彻底变了
你用 Rust 写过一个跑在浏览器里的异步 HTTP 请求吗?
如果有,你大概踩过这个坑:Rust 异步生态在本地跑得好好的,但一到 wasm-bindgen 输出,就发现 async/await 没法直接用——你得给每个 await 包装一层 wrapper,或者干脆把所有 async 调用改成同步回调。TinyGo、Pyodide 也有同样的问题,所以它们都用 Binaryen Asyncify 做 binary rewriting,把 suspend/resume 手工编译成状态机,产物又大又慢,还没法跨运行时移植。
这是因为 WebAssembly 本身一直没有原生的栈切换能力,直到现在。
Wasmtime 46 改变了这件事。
2026 年 6 月 22 日,Wasmtime 46.0.0 正式发布,默认开启 component-model-async,也就是 WASI 0.3 的异步组件模型。这不只是”能用”,而是”默认开启,无需任何 flag”。
这次默认开启意味着什么
之前 WASI 0.3 异步需要两步:规范通过了 + 运行时支持。但规范通过不等于默认能用——你还需要在运行时里加 feature flag 才能打开。很多生产项目卡在这一步:团队评估过了,觉得”还不够成熟”,然后继续用老方案。
Wasmtime 46 把这个门槛彻底移除了。
component-model-async 现在是默认特性,所有 WASI 0.3 异步接口开箱即用。Rust 编译出来的 async 函数直接对应 WASI 0.3 的 future,不需要 binary rewriting,不需要手动状态机,不需要任何 workaround。
生态也在跟上
光一个 Wasmtime 默认开启不够,整个生态链都得跟上才算真正 ready:
wasmCloud 2.5.0(2026-06-30)随 Wasmtime 46 更新,默认 WASI 0.3,移除了旧的 wasip3 feature flag,所有 new-wasmcloud:keyvalue 和 new-wasmcloud:blobstore 接口以 async 形态出货。
Fermyon Spin 4.0.1(2026-06-09)在 Fermyon 被 Akamai 收购后发布,manifest v3 + WASI Preview 3 默认支持。
Jco 1.24.1(2026-06-16)作为 JS/TS 的 Wasm Component 工具链,已完整支持 WASI 0.3 所有特性,Node.js 和浏览器均可用。
这意味着:Rust 编译出的 async Wasm 组件,现在可以在 Wasmtime / wasmCloud / Spin / Jco 上无缝互通,不需要任何转换层。
实际迁移:从 wasm-bindgen 到 Component Model
这是关键区别——wasm-bindgen 走的是浏览器 JS 互操作路径,WASI 0.3 走的是组件模型路径,两者不是替代关系,而是不同的 target。
旧路径(浏览器专用):
[dependencies]
wasm-bindgen = "0.2"
web-sys = { version = "0.3", features = ["FetchOptions"] }
新路径(WASI 0.3 组件,跨运行时):
[dependencies]
wasm-bindgen = "0.2"
# 你现在需要的是这个:
cargo-component = "0.21"
cargo-component 是 Bytecode Alliance 维护的官方工具链,把 Rust 编译成 WIT 接口的 Wasm 组件。生成物是 .wasm 文件,可以在任何 WASI 0.3 运行时里跑,不依赖 JS。
一个简单的 async HTTP handler:
use wasm_bindgen::prelude::*;
use wasi:http/outgoing-handler@0.3.0::*;
#[wasm_bindgen]
pub async fn fetch_data(url: &str) -> Result<String, JsValue> {
let request = OutgoingRequest::new(
&Fields::new(),
Some(Method::Get),
None,
Url::new(url).map_err(|e| JsValue::from_str(&e.to_string()))?,
);
let response = OutgoingHandler::handle(request, None)
.await
.map_err(|e| JsValue::from_str(&e.to_string()))?;
let body = response.body().stream().consume_to_string().await;
Ok(body)
}
注意这个 await——在 Wasmtime 46 之前,这行代码在 Wasm 里跑不了,得手工拆成回调。在 Wasmtime 46 + WASI 0.3 默认开启后,这段代码直接编译运行,不需要任何转换。
几个需要注意的地方
Rust 版本要够新。 Wasmtime 46 要求 Rust 1.93.0 以上(2026-05 月发布),之前提过的 LLVM 19 升级是这次 component-model-async 默认开启的技术基础。如果你还在用旧版 Rust,升级是第一件事。
wasm-bindgen 和 cargo-component 不是二选一。 wasm-bindgen 仍然是 Rust↔JS 互操作的最好工具,适合浏览器内运行的 Wasm。cargo-component 面向的是 WASI 生态——边缘计算、serverless、插件系统。两者针对的场景不同,按需选就行。
生产部署要看运行时支持矩阵。 Wasmtime 46 默认开启,但其他运行时进度不一:Wasmer 7.x 仍在 WASI 0.2 / WASIX 模式,WasmEdge 0.17.0 支持 WASI Preview 2。如果你的目标运行时是 wasmCloud 或 Spin,直接走 WASI 0.3 就好;如果要兼容 Wasmer,还需要再等等。
现在可以用了吗
如果你在做边缘计算、serverless 函数、或者需要跨语言插件系统的场景——Wasmtime 46 默认开启 WASI 0.3,意味着这个技术栈正式从”可以用”变成了”该用了”。
三步下一步:
- 查 Rust 版本:
rustc --version,低于 1.93.0 先升级 - 找一个现有的 wasm-bindgen 项目,评估它是否面向浏览器(用 JS fetch)还是面向服务端(可以用 WASI 0.3 HTTP 接口)
- 用 cargo-component 编译一个最小 WIT 接口的组件,在 Wasmtime 46 里跑起来验证 async await 正常工作
Rust 异步 Wasm 的最大障碍,今天被 Wasmtime 46 默认开启这一步彻底扫掉了。
评论区
登录后可评论。