【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 才会返回,后续代码才会执行。
相关推荐
万少1 小时前
第五款 HarmonyOS 上架作品 奇趣故事匣 来了
前端·harmonyos·客户端
OpenGL1 小时前
Android targetSdkVersion升级至35(Android15)相关问题
前端
rzl021 小时前
java web5(黑马)
java·开发语言·前端
Amy.Wang1 小时前
前端如何实现电子签名
前端·javascript·html5
今天又在摸鱼1 小时前
Vue3-组件化-Vue核心思想之一
前端·javascript·vue.js
蓝婷儿1 小时前
每天一个前端小知识 Day 21 - 浏览器兼容性与 Polyfill 策略
前端
百锦再1 小时前
Vue中对象赋值问题:对象引用被保留,仅部分属性被覆盖
前端·javascript·vue.js·vue·web·reactive·ref
jingling5552 小时前
面试版-前端开发核心知识
开发语言·前端·javascript·vue.js·面试·前端框架
拾光拾趣录2 小时前
CSS 深入解析:提升网页样式技巧与常见问题解决方案
前端·css
莫空00002 小时前
深入理解JavaScript属性描述符:从数据属性到存取器属性
前端·面试