【Tauri】Tauri中Channel的使用

Channel 在 Tauri 中是前端与 Rust 后端进行异步消息通信的桥梁,常用于事件流(如 SSE、WebSocket、长连接)场景。


作用

  • 前端 JS 通过 Channel 实例接收后端 Rust 主动推送的消息。
  • 适合用在"事件驱动"或"流式数据"场景,比如服务端事件(SSE)、实时日志、推送等。

一般用法

1. 前端创建 Channel 并传给 Rust

js 复制代码
import { Channel, invoke } from '@tauri-apps/api/core';

const chan = new Channel();
chan.onmessage = (msg) => {
  // 这里处理 Rust 主动推送的消息
  console.log('收到消息:', msg);
};

const res = await invoke('your_rust_command', { chan }); // 划重点:res何时被打印??

2. Rust 端接收 Channel 并发送消息

rust 复制代码
#[tauri::command]
async fn your_rust_command(chan: tauri::ipc::Channel) {
    // 发送消息到前端
    chan.send("hello from rust!").unwrap();
    // 或循环推送事件
    loop {
        chan.send("实时数据").unwrap();
        tokio::time::sleep(Duration::from_secs(1)).await;
    }
}

问题一:channel 什么时候结束?

  • 只要不调用 destroy_client (即不关闭/移除该 SSE 客户端),Rust 端的 sse_open_stream 里的 loop 就会一直运行,chan.send(...) 会不断推送消息到前端,channel 不会结束

  • 只有当:

rust 复制代码
#[tauri::command]
pub async fn sse_close_stream(url: &str) -> Result<(), String> {
    destroy_client(url.to_string());
    Ok(())
}

问题2: 是不是只要连接一直在res就一直打印不出来,只有断了连接才会走后面的打印?

是的

  • 只要 Rust 端的 sse_open_stream 没有 break(即 SSE 连接还在),await invoke(...) 就会一直 pending,不会执行到 console.log(res)
  • 只有当 SSE 连接断开、出错,或者你主动调用 destroy_client,Rust 端的循环 break,函数返回,res 才会有值,console.log(res) 才会执行。

实例

下面代码中有四个debugger,尝试猜测一下进断点先后顺序

js 复制代码
    const startSSE = async () => {
        const req_url = `${getRcsApiPrefix()}/sse/connect?clientKey=${clientKey}`;
        try {
            let flag = true;
            const chan = new Channel();
            chan.onmessage = async (eve) => {
                debugger // 1
                if (!flag) return;
                const data = JSON.parse(eve);
                if (callback && !callback(data)) {
                    flag = false;
                    await invoke("sse_close_stream", { url: req_url });
                }
            };
            debugger //2
            const res = await invoke("sse_open_stream", { url: req_url, chan });
            console.log(res)
            debugger // 3
            if (res === 1 || (res === 2 && !flag)) {
                timer = setTimeout(() => { startSSE(); }, 25);
            } 
        } catch (error) {
            console.log(`SSE请求失败,尝试重连: ${error}, 时刻: ${new Date()}`);
            timer = setTimeout(() => { startSSE(); }, 3000);
        }
    }
    const closeSSE = async () => {
        debugger // 4
        const req_url = `${getRcsApiPrefix()}/sse/connect?clientKey=${clientKey}`;
        await invoke("sse_close_stream",{url: req_url});

    }

    onMounted(async () => {
        startSSE();
    });
    onUnmounted(async () => {
        sseConnections.clear();
        await closeSSE();
        clearTimeout(timer);
    });

答案:2143

  • 初始化时:先建立Channel,后请求sse_open_stream,先进2;
  • 建立连接后开始实时通信,进入chan.onmessage回调,进入1;
  • 一直通信,await invoke(...) 一直 pending;
  • 离开界面,调用closeSSE(),进入4;
  • 连接销毁,await invoke()结束,res被赋值,进入3。

总结

  • Channel 是 Tauri 前后端异步消息推送的桥梁
  • 前端用 chan.onmessage 监听消息,Rust 端用 chan.send() 主动推送。
  • 适合流式、事件驱动的数据通信。
  • channel 只要不 destroy_client 就不会结束,invoke 也不会返回。
  • 只有连接断开或 destroy_client 后,invoke 才会返回,后续代码才会执行。
相关推荐
灵感__idea3 小时前
JavaScript高级程序设计(第5版):好的编程就是掌控感
前端·javascript·程序员
烛阴4 小时前
Mix
前端·webgl
代码续发5 小时前
前端组件梳理
前端
试图让你心动5 小时前
原生input添加删除图标类似vue里面移入显示删除[jquery]
前端·vue.js·jquery
陈不知代码6 小时前
uniapp创建vue3+ts+pinia+sass项目
前端·uni-app·sass
小王码农记6 小时前
sass中@mixin与 @include
前端·sass
陈琦鹏6 小时前
轻松管理 WebSocket 连接!easy-websocket-client
前端·vue.js·websocket
hui函数6 小时前
掌握JavaScript函数封装与作用域
前端·javascript
行板Andante7 小时前
前端设计中如何在鼠标悬浮时同步修改块内样式
前端
Carlos_sam7 小时前
Opnelayers:ol-wind之Field 类属性和方法详解
前端·javascript