WebSocket封装(TypeScript、单例模式、自动重连、事件监听、Vue中使用)

server/2024/9/19 0:45:23/ 标签: typescript, websocket, 单例模式, vue.js, 前端
export type AutoReconnectOptions = boolean | {maxRetries?: numberretryInterval?: numberonMaxRetriesReached?: Function
}export enum ConnectionStatus {Disconnected = 'DISCONNECTED',Connected = 'CONNECTED',Error = 'ERROR'
}class SocketService {private static instance: SocketServiceprivate ws: WebSocket | null = nullprivate listeners: Record<string, Function[]> = {}private autoReconnect: AutoReconnectOptions = trueprivate retries: number = 0private connectionStatus: ConnectionStatus = ConnectionStatus.Disconnectedprivate constructor() {this.connect()}public static getInstance(): SocketService {if (!SocketService.instance) {SocketService.instance = new SocketService()}return SocketService.instance}public setAutoReconnectOptions(options: AutoReconnectOptions) {this.autoReconnect = options}public connect() {this.ws = new WebSocket('ws://localhost:3000/ws')this.ws.onopen = () => {this.connectionStatus = ConnectionStatus.Connectedthis.emit('connected', null)}this.ws.onerror = () => {this.connectionStatus = ConnectionStatus.Errorthis.emit('error', null)}this.ws.onclose = () => {this.connectionStatus = ConnectionStatus.Disconnectedthis.emit('disconnected', null)if (this.shouldReconnect()) {setTimeout(() => this.connect(), this.getRetryInterval())}}this.ws.onmessage = (event) => {this.emit('message', event.data)}}private shouldReconnect(): boolean {if (typeof this.autoReconnect === 'boolean') {return this.autoReconnect} else if (this.autoReconnect) {const { maxRetries } = this.autoReconnectif (maxRetries !== undefined) {if (this.retries < maxRetries) {this.retries++return true} else if (this.retries >= maxRetries) {this.autoReconnect.onMaxRetriesReached && this.autoReconnect.onMaxRetriesReached()return false}}}return false}private getRetryInterval(): number {if (typeof this.autoReconnect === 'boolean') {return 1000} else if (this.autoReconnect && this.autoReconnect.retryInterval) {return this.autoReconnect.retryInterval}return 1000}public send(data: any) {if (this.ws && this.ws.readyState === WebSocket.OPEN) {this.ws.send(JSON.stringify(data))} else {console.error('WebSocket 连接未打开')}}public close() {if (this.ws) {this.ws.close()}}private emit(event: string, data: any) {if (!this.listeners[event]) {return}this.listeners[event].forEach((listener) => listener(data))}public on(event: string, listener: Function) {if (!this.listeners[event]) {this.listeners[event] = []}this.listeners[event].push(listener)if (event === 'connected' && this.connectionStatus === ConnectionStatus.Connected) {listener()}}public off(event: string, listener: Function) {if (!this.listeners[event]) {return}this.listeners[event] = this.listeners[event].filter((l) => l !== listener)}public getConnectionStatus(): ConnectionStatus {return this.connectionStatus}public watchConnectionStatus(callback: (status: ConnectionStatus) => void) {this.on('connected', () => callback(ConnectionStatus.Connected))this.on('disconnected', () => callback(ConnectionStatus.Disconnected))this.on('error', () => callback(ConnectionStatus.Error))}
}export default SocketService

在 Vue3 中使用:

<script setup lang="ts">
import { onBeforeUnmount, ref } from 'vue'
import SocketService from '@/lib/SocketService'const socketService = SocketService.getInstance()const connectionStatus = ref(socketService.getConnectionStatus())
socketService.watchConnectionStatus((status) => {connectionStatus.value = status
})socketService.setAutoReconnectOptions({maxRetries: 4,retryInterval: 2000,onMaxRetriesReached: () => {console.log('max retries reached')}
})const onConnected = () => {console.log('connected')
}
socketService.on('connected', onConnected)const onDisconnected = () => {console.log('disconnected')
}
socketService.on('disconnected', onDisconnected)const onMessage = (data: any) => {console.log('message', data)
}
socketService.on('message', onMessage)onBeforeUnmount(() => {socketService.off('connected', onConnected)socketService.off('disconnected', onDisconnected)socketService.off('message', onMessage)
})
</script><template><div><div>Connection status: {{ connectionStatus }}</div><button @click="socketService.connect">Connect</button><button @click="socketService.close">Close</button><button @click="socketService.send('Hello')">Send</button></div>
</template>

可以在不同的 Vue 组件/页面中通过 SocketService.getInstance() 获取同一个 WebSocket 连接,监听数据接收以及发送消息。


http://www.ppmy.cn/server/22027.html

相关文章

一、音视频小白入门|搭建 FFmpeg你自己的直播平台

前言 hello&#xff0c;各位读者好&#xff01; 音视频技术作为当今信息时代的重要组成部分&#xff0c;其应用领域日益广泛&#xff0c;无论是在线教育、视频会议&#xff0c;还是直播娱乐、媒体传播&#xff0c;都离不开音视频技术的支持。然而&#xff0c;对于初学者来说&…

c++继承

目录 前言 继承的概念及定义 继承方式与访问限定符 基类和派生类对象赋值转换 隐藏的概念 派生类的默认成员函数 派生类的构造函数 派生类的赋值重载 派生类的析构函数 继承之友元与静态成员 菱形继承及菱形虚继承 单继承 多继承 菱形继承 虚继承原理 继承与组合…

导出excel中的公式,生成python代码

导出excel中的公式,生成python代码 1.思路2.效果3.代码 之前用excel制作了一个llm内存占用量的表格,希望把里面的公式提取出来,生成python代码,供别人使用,以下是demo 1.思路 分别用二列表示变量名和值(值可以是公式)openpyxl load_workbook data_only为False时可以得到cell中…

Linux中的vi与vim:编辑器的王者之争与深度探索

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Linux &#xff1a;从菜鸟到飞鸟的逆袭》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、前言 1、Linux的起源与发展 2、vi与vim的历史与发展 …

闲话 ASP.NET Core 数据校验(一):内置数据校验

前言 所谓输入的是垃圾&#xff0c;输出也必然是垃圾&#xff0c;有多少安全问题隐藏在请求的数据中&#xff0c;所以永远不能相信来自用户端的输入。 对请求数据的合法性进行校验&#xff0c;不仅有助于提升用户界面的友好性&#xff0c;而且有助于提高后台程序的安全性和稳…

SVN仓库勾子脚本中文乱码问题

折腾一天&#xff0c;终于搞定&#xff1a; shell: 添加 export LANGen_US.UTF-8 #!/bin/sh set -eexport LANGen_US.UTF-8REPOS"$1" TXN"$2"# Make sure that the log message contains some text. SVNLOOK/usr/bin/svnlook $SVNLOOK log -t "$T…

Microchip 32位MCU CAN驱动图文教程-附源码

文章目录 创建一个新的32位MCU工程Microchip MCC Harmony配置界面说明在MCC下配置系统的时钟在MCC下配置所需要使用的模块配置调试打印模块配置CAN模块配置管脚功能修改系统堆栈大小生成代码 添加用户代码 创建一个新的32位MCU工程 确保电脑上已经安装最新的MPlab X IDE、XC32编…

vue项目中显示第三方外部链接的页面

1、打开窗口 window.open(URL, name, specs, replace);window.open()方法用于在浏览器中打开一个新的窗口或标签页。如果不指定第二个参数&#xff0c;则链接通常会在当前窗口中打开&#xff0c;这相当于_self。 name 窗口的名称&#xff0c;如果指定相同的名称&#xff0c;那…

Android 当存在双卡时,移动网络默认为SIM卡1

文章目录 一、当Android设备中存在双卡时&#xff0c;移动网络默认为SIM卡1二、下面是完整的代码路径和修改点 一、当Android设备中存在双卡时&#xff0c;移动网络默认为SIM卡1 完成这个需求有以下两个修改点&#xff1a; 下面依旧是Android13 MTK平台&#xff0c;在MtkMulti…

el-table 表格自带全选按钮隐藏

// 隐藏表格的全选当页按钮 // /deep/.el-table { // .el-table__header-wrapper { // .el-table-column--selection { // .el-checkbox { // display: none; // } // } // } // .el-table__fixed { // .el-table__fixed-header-wrapper { // .el-table-column--selection { //…

拉普拉斯IPO:荣获国家级专精特新和国家级制造业单项冠军殊荣

近期&#xff0c;拉普拉斯荣获国家级专精特新和国家级制造业单项冠军的殊荣&#xff0c;这无疑是对其在技术和发展方面的肯定。这些荣誉证明了拉普拉斯在光伏行业的卓越表现和持续创新&#xff0c;以及其在国内制造业中的领先地位&#xff0c;进一步彰显了拉普拉斯在技术研发和…

Linux(文件系统和日志分析)

目录 1.inode & block​编辑 1.1 inode的内容 1.3 inode的号码 1.4 inode的大小 1.5 inode的特殊作用 1.6 模拟inode号被占满 2. 链接文件 3.文件恢复 3.1 修复EXT类型的文件 3.1.1 EXT类型文件恢复步骤 3.2 修复XFS类型的文件 1.inode & block 1.1 in…

边缘计算网关的工业设备数据采集方案-天拓四方

随着工业4.0时代的到来&#xff0c;工业设备数据采集成为了实现智能制造、提升生产效率的关键环节。传统的数据采集方案往往依赖于中心化的数据处理方式&#xff0c;但这种方式在面对海量数据、实时性要求高的工业场景时&#xff0c;往往显得力不从心。因此&#xff0c;利用边缘…

2024程诺申论突击理论刷题班

2024程诺申论突击理论刷题班&#xff0c;为备考者提供了系统而高效的申论学习平台。在这个班里&#xff0c;程诺老师以其深厚的理论功底和丰富的教学经验&#xff0c;引导我们深入理解申论的本质和技巧。刷题环节精心设计&#xff0c;让我们在实战中巩固知识&#xff0c;提升能…

C 语言实例 - 数值比较

比较两个数 以下实例中定义了两个整数变量&#xff0c;并使用 if 来比较两个数值&#xff0c;可以先看下逻辑图&#xff1a; #include <stdio.h>int main() {int a, b;a 11;b 99;// 也可以通过以下代码实现让用户在终端输入两个数// printf("输入第一个值:&quo…

Spring Boot整合Redisson的两种方式

项目场景 Spring Boot整合Redisson的两种方式&#xff0c;方式一直接使用yml配置&#xff0c;方式二创建RedissonConfig配置类。 前言 redisson和redis区别&#xff1a; Redis是一个开源的内存数据库&#xff0c;支持多种数据类型&#xff0c;如字符串、哈希、列表、集合和有序…

普通用户执行source报错,sudo: source:找不到命令的解决方案

一、问题描述 当修改/etc/profile文件&#xff08;环境变量&#xff09;后&#xff0c;想让该环境变量立刻生效。需要执行source命令。命令如下&#xff1a; sudo source /etc/profile 执行这个后&#xff0c;不像别人的执行成功&#xff0c;反而报错了。错误信息如下&#…

eclipse 如何创建python文件

一、准备 1.平台要求&#xff1a; 电脑除了要安装eclipse软件和Python语言包之外&#xff0c;还需要将Python集成到eclipse软件中&#xff0c;网上有很多的方法&#xff0c;这里就不细细介绍如何集成了。 在下面界面中可以看到自己已经安装了继承插件。具体方法见步骤2&…

Linux Makefile编写之可执行程序

1 概述 编译工具有很多(make/cmake/BJam)。如果不考虑跨平台的话&#xff0c;还是make比较方便。使用make编译需要编写Makefile。本文编写Makefile来生成C/C可执行程序。 2 Makefile文件命名 Makefile文件首先是一个文本文件&#xff0c;Linux下默认有两种命名方式: Makefil…

python基础知识

1函数 1.1函数基本结构 def fs(n): if n0: rerurn 1 def()语句可定义函数(函数嵌套定义&#xff0c;Python允许在函数内部定义函数)&#xff0c;其基本格式如下 def函数名(参数值) 函数语句 return返回值 参数值与返回值都可省略也都可有多个 函数调用: 函数名(参…