// class Socket { // constructor(link, ...args) { // // 初始化socket // if (link.constructor === WebSocket) { // this.socket = link; // } else { // this.socket = new WebSocket(link); // } // // this.socket.binaryType = 'arraybuffer'; // this.doOpen(); // // 连接状态的标识符 // this.readyState = this.socket.readyState; // // 订阅/发布模型 // this._events = { // // 订阅的事件 : 发布的方法 // }; // // 定时验证的标识符 // this.heartBeatTimer = null; // } // // 执行socket并发布事件 // doOpen() { // this.afterOpenEmit = []; // // 执行socket连接 并初始化验证请求 // this.socket.addEventListener("open", evt => this.onOpen(evt)); // // 接收socket数据 // this.socket.addEventListener("message", evt => this.onMessage(evt)); // // 关闭socket连接 // this.socket.addEventListener("close", evt => this.onClose(evt)); // // 请求发生错误 // this.socket.addEventListener("error", err => this.onError(err)); // } // // 发布后通知订阅者 // Notify(entry) { // // 检查是否有订阅者 返回队列 // const cbQueue = this._events[entry.Event]; // if (cbQueue && cbQueue.length) { // for (let callback of cbQueue) { // if (callback instanceof Function) callback(entry.Data); // } // } // } // // 请求数据的方法 // onOpen(evt) { // // 每隔20s检查连接 // // this.heartBeatTimer = setInterval(() => this.send({ // // 'cmd': 'ping', // // 'args': '' // // }), 20000); // // 通知订阅 // this.Notify({Event: 'open', Data : evt}); // } // /** // * 订阅所有的数据 // * @param {array|object} datas 订阅参数集合 // */ // send(datas) { // if (datas.constructor != Array) { // datas = [datas]; // } // for (let item of datas) { // this.socket.send(JSON.stringify(item)); // } // } // onMessage(evt) { // try { // // 解析推送的数据 // const data = JSON.parse(evt.data); // // 通知订阅者 // this.Notify({ // Event: 'message', // Data: data // }); // } catch (err) { // console.error(' >> Data parsing error:', err); // // 通知订阅者 // this.Notify({ // Event: 'error', // Data: err // }); // } // } // // 添加事件监听 // on(name, handler) { // this.subscribe(name, handler); // } // // 取消订阅事件 // off(name, handler) { // this.unsubscribe(name, handler); // } // // 订阅事件的方法 // subscribe(name, handler) { // if (this._events.hasOwnProperty(name)) { // this._events[name].push(handler); // 追加事件 // } else { // this._events[name] = [handler]; // 添加事件 // } // } // // 取消订阅事件 // unsubscribe(name, handler) { // let start = this._events[name].findIndex(item => item === handler); // // 删除该事件 // this._events[name].splice(start, 1); // } // checkOpen() { // return this.readyState >= 2; // } // onClose(evt) { // this.Notify({Event: 'close', Data : evt}); // } // onError(err) { // this.Notify({Event: 'error', Data : err}); // } // emit(data) { // return new Promise((resolve) => { // this.send(JSON.stringify(data)); // this.on('message', function (data) { // resolve(data); // }); // }); // } // doClose() { // this.socket.close(); // } // destroy() { // if (this.heartBeatTimer) { // clearInterval(this.heartBeatTimer); // this.heartBeatTimer = null; // } // this.doClose(); // this._events = {}; // this.readyState = 0; // this.socket = null; // } // } // export default Socket class Socket { constructor(link, ...args) { // 修复1:确保 this.link 存的是字符串,方便后面断线重连 if (link.constructor === WebSocket) { this.socket = link; this.link = link.url; } else { this.socket = new WebSocket(link); this.link = link; } this.doOpen(); this.readyState = this.socket.readyState; this._events = {}; this.heartBeatTimer = null; // 新增:重连相关的标识符 this.reconnectTimer = null; this.isReconnecting = false; this.manualClose = false; // 判断是否是用户主动退出页面 } doOpen() { this.afterOpenEmit = []; this.socket.addEventListener("open", evt => this.onOpen(evt)); this.socket.addEventListener("message", evt => this.onMessage(evt)); this.socket.addEventListener("close", evt => this.onClose(evt)); this.socket.addEventListener("error", err => this.onError(err)); } Notify(entry) { const cbQueue = this._events[entry.Event]; if (cbQueue && cbQueue.length) { for (let callback of cbQueue) { if (callback instanceof Function) callback(entry.Data); } } } onOpen(evt) { // 连接成功,重置状态 this.isReconnecting = false; this.manualClose = false; // 每次连上先清空旧的心跳,防止重复 if (this.heartBeatTimer) clearInterval(this.heartBeatTimer); // 每隔20s发送心跳 this.heartBeatTimer = setInterval(() => { this.send({ 'cmd': 'ping', 'args': '' }); }, 20000); this.Notify({Event: 'open', Data : evt}); } send(datas) { if (datas.constructor != Array) { datas = [datas]; } for (let item of datas) { // 修复2:发送前必须检查状态,彻底解决 "CLOSING or CLOSED state" 报错! if (this.socket && this.socket.readyState === 1) { this.socket.send(JSON.stringify(item)); } else { console.warn("WebSocket未连接,已拦截发送请求"); } } } onMessage(evt) { try { const data = JSON.parse(evt.data); this.Notify({ Event: 'message', Data: data }); } catch (err) { console.error(' >> Data parsing error:', err); this.Notify({ Event: 'error', Data: err }); } } on(name, handler) { this.subscribe(name, handler); } off(name, handler) { this.unsubscribe(name, handler); } subscribe(name, handler) { if (this._events.hasOwnProperty(name)) { this._events[name].push(handler); } else { this._events[name] = [handler]; } } unsubscribe(name, handler) { if (!this._events[name]) return; let start = this._events[name].findIndex(item => item === handler); if (start > -1) { this._events[name].splice(start, 1); } } checkOpen() { return this.readyState >= 2; } // 修复3:核心重连逻辑 reconnect() { // 如果是手动关闭(退出页面),或者正在重连中,则放弃重连 if (this.manualClose || this.isReconnecting) return; this.isReconnecting = true; // 断网了,立刻停止发心跳 if (this.heartBeatTimer) { clearInterval(this.heartBeatTimer); this.heartBeatTimer = null; } console.log("WebSocket 掉线,3秒后尝试重新连接..."); this.reconnectTimer = setTimeout(() => { try { this.socket = new WebSocket(this.link); this.doOpen(); } catch (e) { console.error("重连失败", e); // 即使抛出异常也解除锁,等待下一次重连尝试 this.isReconnecting = false; this.reconnect(); return; } }, 3000); } onClose(evt) { this.Notify({Event: 'close', Data : evt}); // 触发关闭时,只要不是主动退出的,就去重连 if (!this.manualClose) this.reconnect(); } onError(err) { this.Notify({Event: 'error', Data : err}); // 发生错误断开时,去重连 if (!this.manualClose) this.reconnect(); } // 修复4:解决内存泄漏,用完立刻注销 emit(data) { return new Promise((resolve) => { this.send(JSON.stringify(data)); const handler = (resData) => { resolve(resData); this.off('message', handler); // 立刻注销,释放内存 }; this.on('message', handler); }); } doClose() { this.manualClose = true; // 标记为主动关闭,防止变成僵尸无限重连 if (this.socket) { this.socket.close(); } } destroy() { this.manualClose = true; if (this.heartBeatTimer) { clearInterval(this.heartBeatTimer); this.heartBeatTimer = null; } if (this.reconnectTimer) { clearTimeout(this.reconnectTimer); this.reconnectTimer = null; } this.doClose(); this._events = {}; this.readyState = 0; this.socket = null; } } export default Socket;