React结合Tauri(Rust)处理百万级CSV事件推送时前端更新卡顿如何解决
问题根源
你遇到的现象本质是事件推送速度远大于前端可处理的上限:
- Rust端每秒可推送数十万条事件,而浏览器的重绘频率最高为60Hz(即每秒最多60次界面更新),大量同步触发的
setAltitude会被React的状态更新机制合并、丢弃,最终只展示最后几次更新的值 - 回调里的
console.log本身会大幅拖慢前端事件处理速度,进一步放大卡顿问题
前端侧优化方案
1. 移除不必要的console打印
这是最容易被忽略的优化点,高频打印会占用大量主线程资源。
2. 对状态更新做节流处理
使用节流函数限制更新频率,匹配浏览器刷新率即可(比如每秒更新30次,完全满足人眼观察需求),不需要处理每一条推送的事件,只需要取最新值更新即可。
修改后的前端代码示例:
// App.js import { listen } from '@tauri-apps/api/event'; import { useEffect, useCallback, useState, useRef } from 'react'; import { invoke } from '@tauri-apps/api/tauri' // 简易节流函数,也可以用lodash的throttle const throttle = (fn, delay) => { let lastCall = 0; return (...args) => { const now = Date.now(); if (now - lastCall >= delay) { lastCall = now; fn(...args); } } } const App = () => { const [altitude, setAltitude] = useState("0"); // 如果需要存储全量数据,用useRef存,不会触发重绘 const allAltitudeRef = useRef([]); const myCallback = useCallback(throttle((e) => { // 如果需要存全量数据就打开下面这行,不会触发重绘 // allAltitudeRef.current.push(e.payload); setAltitude(e.payload); }, 30), []) // 30ms更新一次,也就是每秒约33次 useEffect(() => { const unlisten = listen('rust-event', myCallback); // 组件卸载时取消监听,避免内存泄漏 return () => { unlisten.then(f => f()); } }, [myCallback]) const handleClick = async () => { invoke('my_custom_command').catch(error => console.log(error)); }; return ( <div> <button onClick={handleClick}>Click Me To Start Fetching!</button> <span>{altitude}</span> </div> ); } export default App;
Rust侧优化方案
逐条发送跨进程事件本身开销极高,建议改为批量发送,能大幅降低跨进程通信的压力:
// main.rs 核心修改部分,其他逻辑不变 #[tauri::command] async fn my_custom_command(window: tauri::Window) { // ... 原有schema、文件读取逻辑不变 let mut batch = Vec::with_capacity(1000); // 每攒1000条发一次,可自行调整大小 while let Some(m) = csv.next() { let n = m.unwrap(); let col: &ArrayRef = n.column(0); let col = col.as_any().downcast_ref::<StringArray>().unwrap(); let v = col.value(0); batch.push(v.to_string()); if batch.len() >= 1000 { window.emit("rust-event", &batch).expect("failed to emit"); batch.clear(); } } // 发送剩余不足1000条的部分 if !batch.is_empty() { window.emit("rust-event", &batch).expect("failed to emit"); } }
如果你的业务场景只需要展示最新值,也可以在Rust侧做发送频率限制,比如每20ms发送一次最新值,不需要逐条推送。
内容的提问来源于stack exchange,提问作者Thuy
相关产品推荐
相关产品推荐

