export interface NetworkStatus { isOnline: boolean; lastOnlineTime?: Date; lastOfflineTime?: Date; lastCheck: Date; } export type NetworkStatusCallback = (status: NetworkStatus) => void; export class NetworkService { private static instance: NetworkService; private status: NetworkStatus; private callbacks: Set = new Set(); private checkInterval?: NodeJS.Timeout; private constructor() { const now = new Date(); this.status = { isOnline: navigator.onLine, lastOnlineTime: navigator.onLine ? now : undefined, lastOfflineTime: !navigator.onLine ? now : undefined, lastCheck: now }; this.initializeListeners(); this.startPeriodicCheck(); } public static getInstance(): NetworkService { if (!NetworkService.instance) { NetworkService.instance = new NetworkService(); } return NetworkService.instance; } private initializeListeners(): void { window.addEventListener('online', this.handleOnline.bind(this)); window.addEventListener('offline', this.handleOffline.bind(this)); } private handleOnline(): void { console.log('网络连接已恢复'); this.updateStatus(true); } private handleOffline(): void { console.log('网络连接已断开'); this.updateStatus(false); } private updateStatus(isOnline: boolean): void { const now = new Date(); this.status = { ...this.status, isOnline, lastOnlineTime: isOnline ? now : this.status.lastOnlineTime, lastOfflineTime: !isOnline ? now : this.status.lastOfflineTime, lastCheck: now }; // 通知所有监听器 this.callbacks.forEach(callback => { try { callback(this.status); } catch (error) { console.error('网络状态回调执行错误:', error); } }); } private startPeriodicCheck(): void { // 每30秒检查一次网络连接 this.checkInterval = setInterval(() => { this.checkNetworkConnectivity(); }, 30000); } private async checkNetworkConnectivity(): Promise { try { // 使用浏览器的在线状态作为主要判断依据 const browserOnline = navigator.onLine; if (!browserOnline) { if (this.status.isOnline) { console.log('浏览器检测到网络断开'); this.updateStatus(false); } return; } // 如果浏览器认为在线,直接信任浏览器的判断 // 避免额外的网络请求导致不必要的错误日志 if (browserOnline !== this.status.isOnline) { this.updateStatus(browserOnline); } else { // 即使状态没变,也要更新检查时间 this.status.lastCheck = new Date(); } } catch (error) { // 检测过程出错,保持当前状态 console.warn('网络状态检测出错:', error); } } public getStatus(): NetworkStatus { return { ...this.status }; } public isOnline(): boolean { return this.status.isOnline; } public subscribe(callback: NetworkStatusCallback): () => void { this.callbacks.add(callback); // 立即调用一次回调,提供当前状态 callback(this.status); // 返回取消订阅函数 return () => { this.callbacks.delete(callback); }; } public async waitForOnline(timeout: number = 30000): Promise { if (this.status.isOnline) { return true; } return new Promise((resolve) => { const timeoutId = setTimeout(() => { unsubscribe(); resolve(false); }, timeout); const unsubscribe = this.subscribe((status) => { if (status.isOnline) { clearTimeout(timeoutId); unsubscribe(); resolve(true); } }); }); } public destroy(): void { window.removeEventListener('online', this.handleOnline.bind(this)); window.removeEventListener('offline', this.handleOffline.bind(this)); if (this.checkInterval) { clearInterval(this.checkInterval); } this.callbacks.clear(); } } export const networkService = NetworkService.getInstance(); export default NetworkService;