You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust中两个相似异步函数为何async_trait下Wasm实现报线程安全错误

核心错误原因

你单独编写的run函数可以正常编译,但是适配trait后编译失败,核心原因是#[async_trait]宏的默认约束:

  • 默认情况下#[async_trait]会为trait中的异步方法生成的Future默认加上+ Send约束,你原生端使用reqwest的异步Future满足Send要求,因此原生实现编译正常。
  • Wasm端的JsFuture、所有web-sys包装的JS对象(Request、Response、JsValue等)都没有实现Send trait:浏览器环境下Wasm运行在单线程事件循环中,这些JS对象绑定到当前主线程,不允许跨线程传递,自然不满足Send约束,因此触发编译错误。

解决方案

最简单的方案是修改trait定义的async_trait参数,取消默认的Send强制约束:

// Trait定义时添加?Send参数,表示不强制要求返回的Future实现Send
#[async_trait(?Send)]
pub trait FetchRequest {
    async fn get(&mut self) -> Result<serde_json::Value>;
}

// Wasm端实现同步使用#[async_trait(?Send)]
#[async_trait(?Send)]
impl FetchRequest for WasmFetchRequest {
    async fn get(&mut self) -> Result<serde_json::Value> {
        let mut opts = RequestInit::new();
        opts.method("GET");
        opts.mode(RequestMode::Cors);

        let request = Request::new_with_str_and_init(&self.path, &opts).unwrap();
        request.headers().set("Authorization", &self.authz).unwrap();

        let window = web_sys::window().unwrap();
        let resp_value = JsFuture::from(window.fetch_with_request(&request)).await.unwrap();

        assert!(resp_value.is_instance_of::<Response>());
        let resp: Response = resp_value.dyn_into().unwrap();
        let json = JsFuture::from(resp.json().unwrap()).await.unwrap();
        // 注意修复原有笔误:应该从json转换而不是resp
        let parsed: serde_json::Value = json.into_serde().unwrap();
        Ok(parsed)
    }
}

// 原生端实现也同步使用#[async_trait(?Send)],原有逻辑无需修改
#[async_trait(?Send)]
impl FetchRequest for NativeFetchRequest {
    async fn get(&mut self) -> Result<serde_json::Value> {
        let client = reqwest::Client::new();
        let mut req = client.get(&self.path);
        req = req.header("Authorization", self.authz.as_str());
        let res = req.send().await?;
        res.error_for_status()?
            .json::<serde_json::Value>().await
            .map_err(|err| err.into())
    }
}

?Send约束仅表示“Future不强制要求实现Send”,不会影响原生端的使用:原生端的Future本身还是满足Send要求,在原生多线程环境下依然可以正常跨线程传递Future。


内容的提问来源于stack exchange,提问作者stevs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 14:36:02