// class Socket { // constructor(link) { // // 初始化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[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) { // 保存连接地址,为了后面的断线重连用 this.link = link; // 初始化socket if (link.constructor === WebSocket) { this.socket = link; } else { this.socket = new WebSocket(link); } // 订阅/发布模型 this._events = {}; // 定时验证的标识符 (心跳) this.heartBeatTimer = null; // 重连相关的标识符 this.reconnectTimer = null; this.isReconnecting = false; this.doOpen(); // 连接状态的标识符 this.readyState = this.socket.readyState; } // 执行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); } } } // ✅ 修复 1:开启心跳保活机制,防止半小时后被服务器断开 onOpen(evt) { // 每次连接成功,先清除旧的心跳 if (this.heartBeatTimer) clearInterval(this.heartBeatTimer); // 每隔20s发送一次心跳检查连接 this.heartBeatTimer = setInterval(() => { // 确保是连接状态才发送 if (this.socket && this.socket.readyState === 1) { 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) { if (this.socket && this.socket.readyState === 1) { 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[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; } // ✅ 修复 2:增加断线自动重连机制 reconnect() { if (this.isReconnecting) return; this.isReconnecting = true; // 清除心跳 if (this.heartBeatTimer) clearInterval(this.heartBeatTimer); console.log("WebSocket 掉线,正在尝试重新连接..."); // 延迟3秒重连,防止死循环无限重连导致卡死 this.reconnectTimer = setTimeout(() => { this.socket = new WebSocket(this.link); this.doOpen(); // 重新绑定事件 this.isReconnecting = false; }, 3000); } onClose(evt) { this.Notify({Event: 'close', Data : evt}); this.reconnect(); // 触发关闭时,自动去重连! } onError(err) { this.Notify({Event: 'error', Data : err}); this.reconnect(); // 报错断开时,自动去重连! } // ✅ 修复 3:修复内存泄漏,获取一次数据后立刻销毁监听器 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() { if (this.socket) { this.socket.close(); } } destroy() { if (this.heartBeatTimer) clearInterval(this.heartBeatTimer); if (this.reconnectTimer) clearTimeout(this.reconnectTimer); this.heartBeatTimer = null; this.reconnectTimer = null; this.doClose(); this._events = {}; this.readyState = 0; this.socket = null; } } export default Socket;