mirror of
https://github.com/HuLaSpark/HuLa.git
synced 2026-09-24 23:11:59 +08:00
perf(component): ⚡ 优化webSocket的重连性能和网络检测方法
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
pub mod common_cmd;
|
||||
pub mod init;
|
||||
pub mod network_monitor;
|
||||
pub mod tray;
|
||||
|
||||
@@ -1,216 +0,0 @@
|
||||
use serde::Serialize;
|
||||
use std::net::IpAddr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
use surge_ping::{Client, Config, PingIdentifier, PingSequence};
|
||||
use tauri::{AppHandle, Emitter, Manager, Runtime};
|
||||
use tokio::net::lookup_host;
|
||||
|
||||
// 网络状态枚举
|
||||
#[derive(Debug, Clone, Copy, Serialize, PartialEq)]
|
||||
pub enum NetworkStrength {
|
||||
Strong, // 强网络
|
||||
Weak, // 弱网络
|
||||
Offline, // 离线
|
||||
}
|
||||
|
||||
// 网络状态结构体
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct NetworkStatus {
|
||||
pub is_online: bool,
|
||||
pub strength: NetworkStrength,
|
||||
pub latency_ms: u64, // 延迟时间(毫秒)
|
||||
pub last_check: u64, // 上次检查时间戳
|
||||
}
|
||||
|
||||
impl Default for NetworkStatus {
|
||||
fn default() -> Self {
|
||||
NetworkStatus {
|
||||
is_online: true, // 默认假设在线
|
||||
strength: NetworkStrength::Strong,
|
||||
latency_ms: 0,
|
||||
last_check: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 全局网络状态
|
||||
lazy_static::lazy_static! {
|
||||
static ref NETWORK_STATUS: Arc<Mutex<NetworkStatus>> = Arc::new(Mutex::new(NetworkStatus::default()));
|
||||
}
|
||||
|
||||
// 将域名解析为IP地址
|
||||
async fn resolve_host(host: &str) -> Option<IpAddr> {
|
||||
// 删除可能的协议前缀
|
||||
let host = host.replace("https://", "").replace("http://", "");
|
||||
// 删除可能的路径
|
||||
let host = host.split('/').next().unwrap_or(&host);
|
||||
|
||||
// 使用标准端口进行DNS解析
|
||||
match lookup_host(format!("{host}:80")).await {
|
||||
Ok(mut addrs) => addrs.next().map(|addr| addr.ip()),
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
// 对IP地址进行ping测试
|
||||
async fn ping_ip(ip: IpAddr, count: u8, timeout: Duration) -> Option<u64> {
|
||||
// 注意:Config::builder()没有timeout方法,我们在pinger中设置timeout
|
||||
let config = Config::default();
|
||||
let client = match Client::new(&config) {
|
||||
Ok(client) => client,
|
||||
Err(_) => return None,
|
||||
};
|
||||
|
||||
let mut total_rtt = 0u64;
|
||||
let mut success_count = 0u8;
|
||||
|
||||
for i in 0..count {
|
||||
let payload = vec![0; 56]; // 标准ping数据包大小
|
||||
let ping_id = PingIdentifier(rand::random());
|
||||
// 将u8转换为u16
|
||||
let seq_num = PingSequence(i as u16);
|
||||
|
||||
// 创建pinger(这是一个Future,需要await)
|
||||
// pinger直接返回Pinger对象,不是Result
|
||||
let mut pinger = client.pinger(ip, ping_id).await;
|
||||
// 设置超时(timeout方法返回&mut Pinger,已经修改了原来的pinger)
|
||||
pinger.timeout(timeout);
|
||||
|
||||
// 执行ping
|
||||
match pinger.ping(seq_num, &payload).await {
|
||||
Ok((_, rtt)) => {
|
||||
total_rtt += rtt.as_millis() as u64;
|
||||
success_count += 1;
|
||||
}
|
||||
Err(_) => continue,
|
||||
}
|
||||
}
|
||||
|
||||
if success_count > 0 {
|
||||
Some(total_rtt / success_count as u64)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// 异步检查网络状态
|
||||
async fn check_network_status() -> NetworkStatus {
|
||||
// 测试多个网站以提高准确性
|
||||
let test_hosts = vec!["www.baidu.com", "www.qq.com", "www.aliyun.com"];
|
||||
|
||||
// 200ms的超时时间用于判断弱网
|
||||
let weak_threshold = 200;
|
||||
let ping_timeout = Duration::from_secs(1); // 单次ping超时时间
|
||||
let ping_count = 5; // 每个网站ping 5次
|
||||
|
||||
let now = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_secs();
|
||||
|
||||
// 并发测试所有网站
|
||||
let mut futures = Vec::new();
|
||||
for host in test_hosts {
|
||||
let host = host.to_string();
|
||||
futures.push(tokio::spawn(async move {
|
||||
// 先解析域名
|
||||
if let Some(ip) = resolve_host(&host).await {
|
||||
// 如果解析成功,进行ping测试
|
||||
ping_ip(ip, ping_count, ping_timeout).await
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
// 收集测试结果
|
||||
let mut successful_tests = 0;
|
||||
let mut total_latency = 0u64;
|
||||
|
||||
for future in futures {
|
||||
if let Ok(result) = future.await {
|
||||
if let Some(latency) = result {
|
||||
successful_tests += 1;
|
||||
total_latency += latency;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 根据测试结果判断网络状态
|
||||
if successful_tests == 0 {
|
||||
// 所有测试都失败,认为离线
|
||||
NetworkStatus {
|
||||
is_online: false,
|
||||
strength: NetworkStrength::Offline,
|
||||
latency_ms: 0,
|
||||
last_check: now,
|
||||
}
|
||||
} else {
|
||||
// 至少有一个测试成功,计算平均延迟
|
||||
let avg_latency = total_latency / successful_tests as u64;
|
||||
let strength = if avg_latency > weak_threshold {
|
||||
NetworkStrength::Weak
|
||||
} else {
|
||||
NetworkStrength::Strong
|
||||
};
|
||||
|
||||
NetworkStatus {
|
||||
is_online: true,
|
||||
strength,
|
||||
latency_ms: avg_latency,
|
||||
last_check: now,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新网络状态并通知前端
|
||||
async fn update_network_status<R: Runtime>(app_handle: AppHandle<R>) {
|
||||
let status = check_network_status().await;
|
||||
|
||||
// 获取旧状态进行比较
|
||||
let mut global_status = NETWORK_STATUS.lock().unwrap();
|
||||
let old_status = global_status.clone();
|
||||
|
||||
// 更新全局状态
|
||||
*global_status = status.clone();
|
||||
|
||||
// 如果状态有变化,通知前端
|
||||
if old_status.is_online != status.is_online || old_status.strength != status.strength {
|
||||
// 沿用记忆中的错误处理方式,不抛出错误,而是尝试发送并忽略可能的错误
|
||||
if let Some(window) = app_handle.get_webview_window("home") {
|
||||
let _ = window.emit("network-status-changed", &status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 启动网络监控服务
|
||||
pub fn start_network_monitor<R: Runtime>(app_handle: AppHandle<R>) {
|
||||
let app_handle_clone = app_handle.clone();
|
||||
|
||||
// 立即进行一次检查
|
||||
tauri::async_runtime::spawn(async move {
|
||||
update_network_status(app_handle).await;
|
||||
});
|
||||
|
||||
// 创建后台任务定期检查
|
||||
tauri::async_runtime::spawn(async move {
|
||||
loop {
|
||||
tokio::time::sleep(Duration::from_secs(5)).await; // 每5秒检查一次
|
||||
update_network_status(app_handle_clone.clone()).await;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 获取当前网络状态
|
||||
#[tauri::command]
|
||||
pub fn get_network_status() -> NetworkStatus {
|
||||
NETWORK_STATUS.lock().unwrap().clone()
|
||||
}
|
||||
|
||||
// 手动触发网络状态检查
|
||||
#[tauri::command]
|
||||
pub async fn check_network<R: Runtime>(app_handle: AppHandle<R>) -> NetworkStatus {
|
||||
update_network_status(app_handle.clone()).await;
|
||||
NETWORK_STATUS.lock().unwrap().clone()
|
||||
}
|
||||
@@ -12,8 +12,6 @@ use desktops::common_cmd;
|
||||
#[cfg(desktop)]
|
||||
use desktops::init;
|
||||
#[cfg(desktop)]
|
||||
use desktops::network_monitor::{check_network, get_network_status, start_network_monitor};
|
||||
#[cfg(desktop)]
|
||||
use desktops::tray;
|
||||
#[cfg(desktop)]
|
||||
use init::CustomInit;
|
||||
@@ -49,8 +47,6 @@ fn setup_desktop() {
|
||||
.init_window_event()
|
||||
.setup(move |app| {
|
||||
tray::create_tray(app.handle())?;
|
||||
// 启动网络监测服务
|
||||
start_network_monitor(app.handle().clone());
|
||||
Ok(())
|
||||
})
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
@@ -61,8 +57,6 @@ fn setup_desktop() {
|
||||
set_badge_count,
|
||||
test_api_proxy,
|
||||
test_ws_proxy,
|
||||
get_network_status,
|
||||
check_network,
|
||||
#[cfg(target_os = "macos")]
|
||||
hide_title_bar_buttons
|
||||
])
|
||||
|
||||
@@ -11,18 +11,6 @@
|
||||
当前网络不可用,请检查你的网络设置
|
||||
</n-flex>
|
||||
|
||||
<!-- 弱网提示 -->
|
||||
<n-flex
|
||||
v-if="networkStatus.isOnline.value && networkStatus.networkStrength.value === NetworkStrength.Weak"
|
||||
align="center"
|
||||
justify="center"
|
||||
class="z-999 absolute w-full h-40px rounded-4px text-(12px [--warning-text]) bg-[--warning-bg]">
|
||||
<svg class="size-16px">
|
||||
<use href="#cloudWarning"></use>
|
||||
</svg>
|
||||
当前网络信号较弱,可能影响聊天体验 (延迟: {{ networkStatus.latencyMs.value }}ms)
|
||||
</n-flex>
|
||||
|
||||
<!-- 置顶公告提示 -->
|
||||
<div
|
||||
v-if="isGroup && topAnnouncement"
|
||||
@@ -469,6 +457,7 @@ import { useGlobalStore } from '@/stores/global'
|
||||
import { useDebounceFn } from '@vueuse/core'
|
||||
import { useCachedStore } from '@/stores/cached'
|
||||
import apis from '@/services/apis'
|
||||
import { useNetworkStatus } from '@/hooks/useNetworkStatus'
|
||||
|
||||
const appWindow = WebviewWindow.getCurrent()
|
||||
const { addListener } = useTauriListener()
|
||||
@@ -481,6 +470,7 @@ const userStore = useUserStore()
|
||||
const groupStore = useGroupStore()
|
||||
const globalStore = useGlobalStore()
|
||||
const cachedStore = useCachedStore()
|
||||
const networkStatus = useNetworkStatus()
|
||||
|
||||
// 记录当前滚动位置相关信息
|
||||
const isAutoScrolling = ref(false)
|
||||
@@ -531,10 +521,6 @@ const hoverBubble = ref<{
|
||||
})
|
||||
/** 记录右键菜单时选中的气泡的元素(用于处理mac右键会选中文本的问题) */
|
||||
const recordEL = ref()
|
||||
/** 网络连接是否正常 */
|
||||
// 使用自定义网络状态钩子替代vueuse的useNetwork
|
||||
import { useNetworkStatus, NetworkStrength } from '@/hooks/useNetworkStatus'
|
||||
const networkStatus = useNetworkStatus()
|
||||
const isMac = computed(() => type() === 'macos')
|
||||
// 公告展示时需要减去的高度
|
||||
const announcementHeight = computed(() => (isGroup.value && topAnnouncement.value ? 300 : 260))
|
||||
|
||||
@@ -1,95 +1,42 @@
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
import { listen } from '@tauri-apps/api/event'
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
// 网络状态类型
|
||||
export enum NetworkStrength {
|
||||
Strong = 'Strong',
|
||||
Weak = 'Weak',
|
||||
Offline = 'Offline'
|
||||
}
|
||||
|
||||
// 网络状态接口
|
||||
export interface NetworkStatus {
|
||||
is_online: boolean
|
||||
strength: NetworkStrength
|
||||
latency_ms: number
|
||||
last_check: number
|
||||
}
|
||||
|
||||
/**
|
||||
* 网络状态监测钩子
|
||||
* 提供网络是否在线、网络强度、延迟等信息
|
||||
*/
|
||||
export function useNetworkStatus() {
|
||||
// 网络状态
|
||||
const isOnline = ref(true)
|
||||
// 网络强度
|
||||
const networkStrength = ref<NetworkStrength>(NetworkStrength.Strong)
|
||||
// 网络延迟(毫秒)
|
||||
const latencyMs = ref(0)
|
||||
// 上次检查时间
|
||||
const lastCheck = ref(0)
|
||||
// 网络是否为弱网
|
||||
const isWeakNetwork = ref(false)
|
||||
export const useNetworkStatus = () => {
|
||||
// 网络状态 - 基于浏览器navigator.onLine
|
||||
const isOnline = ref(navigator.onLine)
|
||||
|
||||
// 存储监听器清理函数
|
||||
let unlisten: (() => void) | null = null
|
||||
|
||||
// 初始化网络状态
|
||||
const initNetworkStatus = async () => {
|
||||
try {
|
||||
const status = await invoke<NetworkStatus>('get_network_status')
|
||||
updateNetworkStatus(status)
|
||||
} catch (error) {
|
||||
console.error('获取网络状态失败:', error)
|
||||
}
|
||||
// 监听浏览器网络状态变化
|
||||
const handleOnline = () => {
|
||||
isOnline.value = true
|
||||
}
|
||||
|
||||
// 手动检查网络状态
|
||||
const checkNetwork = async () => {
|
||||
try {
|
||||
const status = await invoke<NetworkStatus>('check_network')
|
||||
updateNetworkStatus(status)
|
||||
return status
|
||||
} catch (error) {
|
||||
console.error('检查网络状态失败:', error)
|
||||
return null
|
||||
}
|
||||
const handleOffline = () => {
|
||||
isOnline.value = false
|
||||
}
|
||||
|
||||
// 更新网络状态
|
||||
const updateNetworkStatus = (status: NetworkStatus) => {
|
||||
isOnline.value = status.is_online
|
||||
networkStrength.value = status.strength
|
||||
latencyMs.value = status.latency_ms
|
||||
lastCheck.value = status.last_check
|
||||
isWeakNetwork.value = status.strength === NetworkStrength.Weak
|
||||
// 初始化网络状态监听
|
||||
const initNetworkListener = () => {
|
||||
window.addEventListener('online', handleOnline)
|
||||
window.addEventListener('offline', handleOffline)
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
// 初始化网络状态
|
||||
await initNetworkStatus()
|
||||
// 清理网络状态监听
|
||||
const cleanupNetworkListener = () => {
|
||||
window.removeEventListener('online', handleOnline)
|
||||
window.removeEventListener('offline', handleOffline)
|
||||
}
|
||||
|
||||
// 监听网络状态变化事件
|
||||
unlisten = await listen<NetworkStatus>('network-status-changed', (event) => {
|
||||
updateNetworkStatus(event.payload)
|
||||
})
|
||||
})
|
||||
// 自动初始化监听器
|
||||
initNetworkListener()
|
||||
|
||||
// 在组件卸载时清理监听器
|
||||
onUnmounted(() => {
|
||||
// 清理监听器
|
||||
if (unlisten) {
|
||||
unlisten()
|
||||
}
|
||||
cleanupNetworkListener()
|
||||
})
|
||||
|
||||
return {
|
||||
isOnline,
|
||||
networkStrength,
|
||||
latencyMs,
|
||||
lastCheck,
|
||||
isWeakNetwork,
|
||||
checkNetwork
|
||||
initNetworkListener,
|
||||
cleanupNetworkListener
|
||||
}
|
||||
}
|
||||
|
||||
+94
-22
@@ -31,14 +31,48 @@ const timerWorker: Worker = new Worker(new URL('../workers/timer.worker.ts', imp
|
||||
// 添加一个标识是否是主窗口的变量
|
||||
let isMainWindow = false
|
||||
|
||||
// LRU缓存实现
|
||||
class LRUCache<K, V> {
|
||||
private maxSize: number
|
||||
private cache = new Map<K, V>()
|
||||
|
||||
constructor(maxSize: number = 1000) {
|
||||
this.maxSize = maxSize
|
||||
}
|
||||
|
||||
set(key: K, value: V) {
|
||||
if (this.cache.has(key)) {
|
||||
this.cache.delete(key)
|
||||
} else if (this.cache.size >= this.maxSize) {
|
||||
const firstKey = this.cache.keys().next().value
|
||||
if (firstKey) {
|
||||
this.cache.delete(firstKey)
|
||||
}
|
||||
}
|
||||
this.cache.set(key, value)
|
||||
}
|
||||
|
||||
has(key: K): boolean {
|
||||
return this.cache.has(key)
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.cache.clear()
|
||||
}
|
||||
|
||||
get size(): number {
|
||||
return this.cache.size
|
||||
}
|
||||
}
|
||||
|
||||
class WS {
|
||||
// 添加消息队列大小限制
|
||||
readonly #MAX_QUEUE_SIZE = 100
|
||||
readonly #MAX_QUEUE_SIZE = 50 // 减少队列大小
|
||||
#tasks: WsReqMsgContentType[] = []
|
||||
// 重连🔐
|
||||
#connectReady = false
|
||||
// 使用LRU缓存替代简单的Set
|
||||
#processedMsgCache = new Map<number, number>()
|
||||
#processedMsgCache = new LRUCache<number, number>(1000) // 使用LRU缓存
|
||||
|
||||
#tauriListener: ReturnType<typeof useTauriListener> | null = null
|
||||
|
||||
@@ -112,13 +146,13 @@ class WS {
|
||||
})
|
||||
)
|
||||
|
||||
// 如果从不可见变为可见状态,并且网络重连工具已初始化,检查是否需要刷新数据
|
||||
// 优化的可见性恢复检查
|
||||
if (isVisible && this.#networkReconnect?.isOnline?.value) {
|
||||
// 检查最后一次通信时间,如果太久没有通信,刷新数据
|
||||
const now = Date.now()
|
||||
const lastPongTime = this.#connectionHealth.lastPongTime
|
||||
if (lastPongTime && now - lastPongTime > 60000) {
|
||||
// 如果超过1分钟没有心跳
|
||||
const heartbeatTimeout = 90000 // 增加到90秒,减少误触发
|
||||
if (lastPongTime && now - lastPongTime > heartbeatTimeout) {
|
||||
console.log('[Network] 应用从后台恢复且长时间无心跳,刷新数据')
|
||||
this.#networkReconnect?.refreshAllData()
|
||||
}
|
||||
@@ -384,10 +418,19 @@ class WS {
|
||||
if (this.#connectReady) {
|
||||
this.#send(params)
|
||||
} else {
|
||||
// 队列限制
|
||||
// 优化的队列管理
|
||||
if (this.#tasks.length >= this.#MAX_QUEUE_SIZE) {
|
||||
console.warn('消息队列已满,正在丢弃最旧的消息')
|
||||
this.#tasks.shift()
|
||||
// 优先丢弃非关键消息
|
||||
const nonCriticalIndex = this.#tasks.findIndex(
|
||||
(task) => typeof task === 'object' && task.type !== 1 && task.type !== 2
|
||||
)
|
||||
if (nonCriticalIndex !== -1) {
|
||||
this.#tasks.splice(nonCriticalIndex, 1)
|
||||
console.warn('消息队列已满,丢弃非关键消息')
|
||||
} else {
|
||||
this.#tasks.shift()
|
||||
console.warn('消息队列已满,丢弃最旧消息')
|
||||
}
|
||||
}
|
||||
this.#tasks.push(params)
|
||||
}
|
||||
@@ -597,21 +640,50 @@ class WS {
|
||||
}
|
||||
|
||||
destroy() {
|
||||
worker.postMessage(JSON.stringify({ type: 'clearReconnectTimer' }))
|
||||
worker.terminate()
|
||||
// 同时终止timer worker相关的心跳
|
||||
timerWorker.postMessage({
|
||||
type: 'stopPeriodicHeartbeat'
|
||||
})
|
||||
this.#tasks = []
|
||||
this.#processedMsgCache.clear()
|
||||
this.#connectReady = false
|
||||
// 清理 Tauri 事件监听器
|
||||
this.#tauriListener?.cleanup()
|
||||
try {
|
||||
// 优化的资源清理顺序
|
||||
worker.postMessage(JSON.stringify({ type: 'clearReconnectTimer' }))
|
||||
worker.postMessage(JSON.stringify({ type: 'stopHeartbeat' }))
|
||||
|
||||
// 清理所有watch
|
||||
this.#unwatchFunctions.forEach((unwatch) => unwatch())
|
||||
this.#unwatchFunctions = []
|
||||
// 同时终止timer worker相关的心跳
|
||||
timerWorker.postMessage({
|
||||
type: 'stopPeriodicHeartbeat'
|
||||
})
|
||||
|
||||
// 清理内存
|
||||
this.#tasks.length = 0 // 更高效的数组清空
|
||||
this.#processedMsgCache.clear()
|
||||
this.#connectReady = false
|
||||
|
||||
// 重置连接健康状态
|
||||
this.#connectionHealth = {
|
||||
isHealthy: true,
|
||||
lastPongTime: null,
|
||||
timeSinceLastPong: null
|
||||
}
|
||||
|
||||
// 清理 Tauri 事件监听器
|
||||
this.#tauriListener?.cleanup()
|
||||
this.#tauriListener = null
|
||||
|
||||
// 清理所有watch
|
||||
this.#unwatchFunctions.forEach((unwatch) => {
|
||||
try {
|
||||
unwatch()
|
||||
} catch (error) {
|
||||
console.warn('清理watch函数时出错:', error)
|
||||
}
|
||||
})
|
||||
this.#unwatchFunctions.length = 0
|
||||
|
||||
// 最后终止workers
|
||||
setTimeout(() => {
|
||||
worker.terminate()
|
||||
timerWorker.terminate()
|
||||
}, 100) // 给一点时间让消息处理完成
|
||||
} catch (error) {
|
||||
console.error('销毁WebSocket时出错:', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-11
@@ -24,17 +24,20 @@ const checkAllTimersCompleted = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 添加调试信息打印函数
|
||||
// 优化的调试信息打印函数
|
||||
const logDebugInfo = (msgId: number, remainingTime: number) => {
|
||||
// 只有开启日志功能时才打印
|
||||
if (enableLogging) {
|
||||
// 只有开启日志功能时才打印,且只在关键时间点打印
|
||||
if (enableLogging && (remainingTime <= 5000 || remainingTime % 10000 < 1000)) {
|
||||
console.log(`[Worker Debug] 消息ID: ${msgId}, 剩余时间: ${(remainingTime / 1000).toFixed(1)}秒`)
|
||||
self.postMessage({
|
||||
type: 'debug',
|
||||
msgId,
|
||||
remainingTime,
|
||||
timestamp: Date.now()
|
||||
})
|
||||
// 减少向主线程发送调试消息的频率
|
||||
if (remainingTime <= 3000) {
|
||||
self.postMessage({
|
||||
type: 'debug',
|
||||
msgId,
|
||||
remainingTime,
|
||||
timestamp: Date.now()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +106,8 @@ self.onmessage = (e) => {
|
||||
// 立即打印一次初始状态
|
||||
logDebugInfo(msgId, duration)
|
||||
|
||||
// 创建定时打印的间隔器,每1000ms打印一次
|
||||
// 优化的调试间隔器,减少打印频率
|
||||
const debugInterval = duration > 10000 ? 5000 : 1000 // 长任务每5秒打印,短任务每秒打印
|
||||
const debugId = setInterval(() => {
|
||||
const elapsed = Date.now() - startTime
|
||||
const remaining = duration - elapsed
|
||||
@@ -112,7 +116,7 @@ self.onmessage = (e) => {
|
||||
} else {
|
||||
clearInterval(debugId)
|
||||
}
|
||||
}, 1000) // 每秒打印一次
|
||||
}, debugInterval)
|
||||
|
||||
const timerId = setTimeout(() => {
|
||||
clearInterval(debugId)
|
||||
|
||||
@@ -129,27 +129,35 @@ const sendSingleHeartbeat = () => {
|
||||
return
|
||||
}
|
||||
|
||||
// 检测连接健康状态
|
||||
// 优化的连接健康检测机制
|
||||
if (lastPongTime !== null) {
|
||||
const timeSinceLastPong = lastPingSent - lastPongTime
|
||||
const isConnectionHealthy = timeSinceLastPong < HEARTBEAT_INTERVAL * 2
|
||||
const healthThreshold = HEARTBEAT_INTERVAL * 2.5 // 增加容错时间
|
||||
const isConnectionHealthy = timeSinceLastPong < healthThreshold
|
||||
|
||||
// 如果连接不健康,通知主线程
|
||||
if (!isConnectionHealthy) {
|
||||
consecutiveHeartbeatFailures++
|
||||
logHeartbeat('连接响应缓慢', {
|
||||
consecutiveFailures: consecutiveHeartbeatFailures,
|
||||
timeSinceLastPong
|
||||
})
|
||||
|
||||
postMsg({
|
||||
type: WorkerMsgEnum.ERROR,
|
||||
value: {
|
||||
msg: '连接响应较慢,可能存在网络问题',
|
||||
timeSinceLastPong,
|
||||
consecutiveFailures: consecutiveHeartbeatFailures
|
||||
}
|
||||
})
|
||||
// 只在关键阈值时记录日志,减少日志开销
|
||||
if (consecutiveHeartbeatFailures === 1 || consecutiveHeartbeatFailures % 3 === 0) {
|
||||
logHeartbeat('连接响应缓慢', {
|
||||
consecutiveFailures: consecutiveHeartbeatFailures,
|
||||
timeSinceLastPong
|
||||
})
|
||||
}
|
||||
|
||||
// 延迟错误通知,避免频繁触发
|
||||
if (consecutiveHeartbeatFailures >= 2) {
|
||||
postMsg({
|
||||
type: WorkerMsgEnum.ERROR,
|
||||
value: {
|
||||
msg: '连接响应较慢,可能存在网络问题',
|
||||
timeSinceLastPong,
|
||||
consecutiveFailures: consecutiveHeartbeatFailures
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 连续失败次数过多,尝试重连
|
||||
if (consecutiveHeartbeatFailures >= MAX_HEARTBEAT_FAILURES) {
|
||||
@@ -244,11 +252,15 @@ const tryReconnect = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 优化的智能退避算法
|
||||
const getBackoffDelay = (retryCount: number) => {
|
||||
const baseDelay = 1000 // 基础延迟1秒
|
||||
const maxDelay = 30000 // 最大延迟30秒
|
||||
const delay = Math.min(baseDelay * Math.pow(2, retryCount), maxDelay)
|
||||
return delay + Math.random() * 1000 // 添加随机抖动
|
||||
const maxDelay = 15000 // 减少最大延迟到15秒
|
||||
const multiplier = Math.min(1.5, 2 - retryCount * 0.1)
|
||||
const delay = Math.min(baseDelay * Math.pow(multiplier, retryCount), maxDelay)
|
||||
|
||||
// 减少随机抖动范围
|
||||
return delay + Math.random() * 500
|
||||
}
|
||||
|
||||
const onCloseHandler = () => {
|
||||
|
||||
Reference in New Issue
Block a user