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 不会结束。 -
只有当:
- 收到 rx.recv()(即 destroy_client 被调用,或 sse_close_stream 被前端 invoke),或者
- SSE 流断开/出错/服务端关闭 才会 break 退出循环,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 才会返回,后续代码才会执行。