写过 Wasm 的工程师大概都踩过这个坑——Rust 跑在浏览器里,每次调 fetch() 都要绕 JS,今天 wasm32-component 把这件事彻底原生化了

写过 Wasm 的工程师大概都踩过这个坑——Rust 跑在浏览器里,要调个 fetch(),得先塞给 JavaScript 一段胶水代码,等它回调回来,再手动把值转回 Rust 类型。wasm32-unknown-unknown 这个 target 十年没变,社区只能靠 wasm-bindgen 手动抹平两侧的类型系统,每次跨语言都要写一坨 #[wasm_bindgen] 补丁。

这件事,2026 年的 Rust 正在从根上原生化了。

wasm32-wasip3:从回调地狱到原生 async/await

WASI 0.3 在 2026 年 6 月正式发布,最核心的变化是把 async/await 做进了 Component Model 的 ABI 层。在此之前,Wasm 模块做异步 I/O 只有两条路:要么阻塞线程(吞吐直接崩),要么自己实现状态机再映射到 Wasm 的同步执行模型(复杂且不可移植)。WASI 0.3 引入了 stream 和 future 两种原生类型,运行时现在可以在 Wasm 组件之间协作调度 I/O 工作,完全不需要开发者手动介入。

举个例子,WASI 0.2 时代的 HTTP handler 长这样:

// WASI 0.2:必须用回调,写起来像手绕电线
fn handle(req: IncomingRequest, response_out: ResponseOutparam) {
    req.consume().unwrap() // 同步阻塞
}

WASI 0.3 之后:

// WASI 0.3:直接 async fn,跟写普通 Rust 服务端一模一样
use wasi::http::types::{IncomingRequest, ResponseOutparam};

#[wasi::async_main]
async fn handle(req: IncomingRequest, response_out: ResponseOutparam) {
    let body = req.consume().await.unwrap();       // 非阻塞 I/O
    let data = body.read(4096).await.unwrap();    // 流式读取
    ResponseOutparam::set(response_out, Ok(build_response(200, process(&data))));
}

这意味着什么?Rust 写的 Wasm 模块第一次可以真正做高性能网络服务了——边缘函数的冷启动本来就是微秒级,现在加上原生 async,并发 I/O 不再是特种需求。

三条新 target 补全了什么

Rust 2026 路线图里,Wasm Component 支持分了三路:

Target 定位 关键特性
wasm32-wasip3 服务端/边缘计算 原生 async,输出 Wasm Component,默认启用
wasm32-component 纯组件(无 std) 只带 core + alloc,不依赖操作系统,适合插件系统
wasm32-component-web 浏览器端 等同 wasm32-component,但带 #[cfg(web)] 条件编译,访问 Web API

之前 Rust 缺一个正经的”浏览器 target”——wasm32-unknown-unknown 没有系统接口,生态靠 wasm-bindgen 手动桥接,第三方库碎片化严重。wasm32-component-web 一旦落地,Rust 代码可以直接调用 Web API 而不用绕 JS,更关键的是:同一套 WIT 接口定义,可以同时编译给浏览器、给 Wasmtime、给 Cloudflare Workers

WIT:让 Rust 和 Python 互调不再需要 JSON

Component Model 之所以成立,WIT(Wasm Interface Types)是地基。这是一个语言无关的 IDL,描述组件暴露和消费哪些类型和函数。不同语言只需要各自的 wit-bindgen 工具就能自动生成类型安全的绑定,跨边界传递数据是零序列化的。

// storage.wit
package myorg:storage;
interface kv-store {
    record entry {
        key: string,
        value: list<u8>,
        ttl-seconds: option<u32>,
    }
    get: func(key: string) -> option<entry>;
    set: func(entry: entry) -> result;
}
world storage-world {
    export kv-store;
}

用 Rust 实现这个接口,wit-bindgen 0.58.0 直接生成调用代码。Python、JavaScript、Go 各自同样生成 bindings,互相调用不需要 JSON,不需要 HTTP,直接内存级传递。这在以前是每个团队自己造轮子的 FFI 地狱,现在成了标准配置。

现状与下一步

wasm32-wasip3 目前是 Tier 3(需手动 rustup target add wasm32-wasip3),要配 wasi-sdk 22 才能编译。但 wasm32-component 和 wasm32-component-web 是 2026 路线图目标,WASI 1.0 预计 2026 年底/2027 年初正式发布,届时会是第一个有长期维护承诺的 WASI 版本。

如果你的场景是边缘计算或插件系统,现在可以开始用 wasm32-wasip3 跑了。如果是浏览器端,现阶段还是老实走 wasm-bindgen + wasm32-unknown-unknown,等 wasm32-component-web 就绪后再迁。

三步上手:

  1. rustup target add wasm32-wasip3(需 wasi-sdk 22)
  2. 写一个 #[wasi::async_main] 的 HTTP handler
  3. cargo build --target wasm32-wasip3 --release,产物丢进 Wasmtime 或 Cloudflare Workers 直接跑

Wasm 在 Rust 里不再只是”编译过去能跑”的备选方案,而是真正原生的第一等公民。

评论区

0 条评论

登录后可评论。

铁锈·Rust工具链 12 阅读