当前位置: 首页 > news >正文

最佳websocket封装

封装了weboskect,完美支持了断网重连、自动心跳的功能,且完全兼容原生写法,无任何学习负担,开开箱即用!

import { EventDispatcher } from './dispatcher';export class WebSocketClient extends EventDispatcher {// #socket链接url = '';// #socket实例socket = null;// #重连次数reconnectAttempts = 0;// #最大重连数maxReconnectAttempts = 5;// #重连间隔reconnectInterval = 10000; // 10 seconds// #发送心跳数据间隔heartbeatInterval = 1000 * 30;// #计时器idheartbeatTimer = undefined;// #彻底终止wsstopWs = false;// *构造函数constructor(url) {super();this.url = url;}// >生命周期钩子onopen(callBack) {this.addEventListener('open', callBack);}onmessage(callBack) {this.addEventListener('message', callBack);}onclose(callBack) {this.addEventListener('close', callBack);}onerror(callBack) {this.addEventListener('error', callBack);}// >消息发送send(message) {if (this.socket && this.socket.readyState === WebSocket.OPEN) {this.socket.send(message);} else {console.error('[WebSocket] 未连接');}}// !初始化连接connect() {if (this.reconnectAttempts === 0) {this.log('WebSocket', `初始化连接中...          ${this.url}`);}if (this.socket && this.socket.readyState === WebSocket.OPEN) {return;}this.socket = new WebSocket(this.url);// !websocket连接成功this.socket.onopen = event => {this.stopWs = false;// 重置重连尝试成功连接this.reconnectAttempts = 0;// 在连接成功时停止当前的心跳检测并重新启动this.startHeartbeat();this.log('WebSocket', `连接成功,等待服务端数据推送[onopen]...     ${this.url}`);this.dispatchEvent('open', event);};this.socket.onmessage = event => {this.dispatchEvent('message', event);this.startHeartbeat();};this.socket.onclose = event => {if (this.reconnectAttempts === 0) {this.log('WebSocket', `连接断开[onclose]...    ${this.url}`);}if (!this.stopWs) {this.handleReconnect();}this.dispatchEvent('close', event);};this.socket.onerror = event => {if (this.reconnectAttempts === 0) {this.log('WebSocket', `连接异常[onerror]...    ${this.url}`);}this.closeHeartbeat();this.dispatchEvent('error', event);};}// > 断网重连逻辑handleReconnect() {if (this.reconnectAttempts < this.maxReconnectAttempts) {this.reconnectAttempts++;this.log('WebSocket', `尝试重连... (${this.reconnectAttempts}/${this.maxReconnectAttempts})       ${this.url}`);setTimeout(() => {this.connect();}, this.reconnectInterval);} else {this.closeHeartbeat();this.log('WebSocket', `最大重连失败,终止重连: ${this.url}`);}}// >关闭连接close() {if (this.socket) {this.stopWs = true;this.socket.close();this.socket = null;this.removeEventListener('open');this.removeEventListener('message');this.removeEventListener('close');this.removeEventListener('error');}this.closeHeartbeat();}// >开始心跳检测 -> 定时发送心跳消息startHeartbeat() {if (this.stopWs) return;if (this.heartbeatTimer) {this.closeHeartbeat();}this.heartbeatTimer = setInterval(() => {if (this.socket) {this.socket.send(JSON.stringify({ type: 'heartBeat', data: {} }));this.log('WebSocket', '送心跳数据...');} else {console.error('[WebSocket] 未连接');}}, this.heartbeatInterval);}// >关闭心跳closeHeartbeat() {clearInterval(this.heartbeatTimer);this.heartbeatTimer = undefined;}
}
class Log {static console = true;log(title, text) {if (!Log.console) return;if (import.meta.env.MODE === 'production') return;const color = '#ff4d4f';console.log(`%c ${title} %c ${text} %c`,`background:${color};border:1px solid ${color}; padding: 1px; border-radius: 2px 0 0 2px; color: #fff;`,`border:1px solid ${color}; padding: 1px; border-radius: 0 2px 2px 0; color: ${color};`,'background:transparent');}closeConsole() {Log.console = false;}
}
export class EventDispatcher extends Log {listeners = {};addEventListener(type, listener) {if (!this.listeners[type]) {this.listeners[type] = [];}if (this.listeners[type].indexOf(listener) === -1) {this.listeners[type].push(listener);}}removeEventListener(type) {this.listeners[type] = [];}dispatchEvent(type, data) {const listenerArray = this.listeners[type] || [];if (listenerArray.length === 0) return;listenerArray.forEach(listener => {listener.call(this, data);});}
}

相关文章:

  • java8 List的Stream流操作 (实用篇 三)
  • 【Effective Web】常见的css布局方式--三栏布局
  • 网络安全:SQL注入防范
  • 在 React 中使用 ArcGIS JavaScript SDK 构建地图应用
  • STM32高级控制定时器(STM32F103):PWM输出模式
  • 数据赋能(122)——体系:数据清洗——技术方法、主要工具
  • AWS 批量添加安全组
  • Hi3861 OpenHarmony嵌入式应用入门--点灯
  • 图像识别技术在虚拟现实与增强现实中的应用
  • 数实融合创新发展 隆道分享企业级AI应用
  • C语言:文件操作
  • 保姆级pycharm远程连接linux服务器
  • QT——MySQL数据库联用
  • Windows CSC服务特权提升漏洞(CVE-2024-26229)
  • uniapp 微信小程序更改轮播图指示点
  • [ JavaScript ] 数据结构与算法 —— 链表
  • 【跃迁之路】【519天】程序员高效学习方法论探索系列(实验阶段276-2018.07.09)...
  • 5分钟即可掌握的前端高效利器:JavaScript 策略模式
  • Android开发 - 掌握ConstraintLayout(四)创建基本约束
  • hadoop集群管理系统搭建规划说明
  • HashMap ConcurrentHashMap
  • Java反射-动态类加载和重新加载
  • Js基础——数据类型之Null和Undefined
  • underscore源码剖析之整体架构
  • 利用jquery编写加法运算验证码
  • 码农张的Bug人生 - 初来乍到
  • 在weex里面使用chart图表
  • 扩展资源服务器解决oauth2 性能瓶颈
  • 我们雇佣了一只大猴子...
  • ​LeetCode解法汇总2182. 构造限制重复的字符串
  • ​无人机石油管道巡检方案新亮点:灵活准确又高效
  • ‌JavaScript 数据类型转换
  • # Pytorch 中可以直接调用的Loss Functions总结:
  • $Django python中使用redis, django中使用(封装了),redis开启事务(管道)
  • (2022 CVPR) Unbiased Teacher v2
  • (C语言)逆序输出字符串
  • (leetcode学习)236. 二叉树的最近公共祖先
  • (第二周)效能测试
  • (二十五)admin-boot项目之集成消息队列Rabbitmq
  • (函数)颠倒字符串顺序(C语言)
  • (图文详解)小程序AppID申请以及在Hbuilderx中运行
  • (原)记一次CentOS7 磁盘空间大小异常的解决过程
  • *2 echo、printf、mkdir命令的应用
  • *Django中的Ajax 纯js的书写样式1
  • .\OBJ\test1.axf: Error: L6230W: Ignoring --entry command. Cannot find argumen 'Reset_Handler'
  • .NET Framework 和 .NET Core 在默认情况下垃圾回收(GC)机制的不同(局部变量部分)
  • .Net FrameWork总结
  • .net wcf memory gates checking failed
  • .NET Windows:删除文件夹后立即判断,有可能依然存在
  • .NET 漏洞分析 | 某ERP系统存在SQL注入
  • .net 使用$.ajax实现从前台调用后台方法(包含静态方法和非静态方法调用)
  • .NET轻量级ORM组件Dapper葵花宝典
  • /bin/bash^M: bad interpreter: No such file ordirectory
  • ?
  • @DateTimeFormat 和 @JsonFormat 注解详解