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

如何从Wasm向JavaScript返回含非Copy/Clone类型的元组?

实现方案

要解决Wasm中返回futures通道收发器的问题,我们可以分别包装Sender和Receiver,通过暴露异步方法让JavaScript侧正常调用,同时保证单一所有权需求,具体实现如下:

1. 依赖准备

首先在Cargo.toml中添加所需依赖:

[dependencies]
wasm-bindgen = "0.2"
futures = "0.3"
wasm-bindgen-futures = "0.4"
js-sys = "0.3"

2. 包装收发器并暴露方法

use futures::{channel::mpsc, stream::Stream, StreamExt};
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::JsFuture;
use js_sys::Promise;

#[wasm_bindgen]
pub struct WrappedSender {
    sender: mpsc::Sender<i32>,
}

#[wasm_bindgen]
impl WrappedSender {
    // 暴露发送方法,返回Promise表示发送结果
    pub fn send(&mut self, value: i32) -> Promise {
        let sender = self.sender.clone();
        JsFuture::from(async move {
            sender.send(value).await
                .map_err(|e| JsValue::from_str(&format!("发送失败: {:?}", e)))?;
            Ok(JsValue::UNDEFINED)
        }).into()
    }
}

#[wasm_bindgen]
pub struct WrappedReceiver {
    receiver: Pin<Box<dyn Stream<Item = i32> + 'static>>,
}

#[wasm_bindgen]
impl WrappedReceiver {
    // 暴露获取下一个元素的方法,返回Promise,元素存在时返回数值,流结束返回null
    pub fn next(&mut self) -> Promise {
        let mut receiver = self.receiver.as_mut();
        JsFuture::from(async move {
            match receiver.next().await {
                Some(val) => Ok(JsValue::from(val)),
                None => Ok(JsValue::NULL),
            }
        }).into()
    }
}

#[wasm_bindgen]
pub fn channel() -> (WrappedSender, WrappedReceiver) {
    let (tx, rx) = mpsc::channel(32);
    (
        WrappedSender { sender: tx },
        WrappedReceiver { receiver: Box::pin(rx) },
    )
}

3. 关键细节说明

  • 所有权保证:WrappedReceiver内部持有Pin<Box<dyn Stream>>,通过&mut self调用next方法,确保对接收流的独占可变访问,无需Rc<RefCell>这类多所有权包装,符合单一所有权需求。
  • JavaScript兼容性:返回的元组可直接在JS中解构,例如:
    import { channel } from './pkg/your_wasm_module.js';
    
    async function useChannel() {
        const [sender, receiver] = channel();
        // 发送数据
        await sender.send(42);
        // 接收数据
        const val = await receiver.next();
        console.log(val); // 输出42
    }
    
  • 异步适配:借助wasm_bindgen_futures将Rust的Future转换为JS的Promise,让两端异步逻辑无缝对接。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 00:20:06