前端实现websocket类封装
随着Web应用程序的发展,越来越多的人开始利用Websocket技术来构建实时应用程序。Websocket是一种在客户端和服务器之间建立持久连接的协议。这种协议可以在一个单独的连接上实现双向通信。与HTTP请求-响应模型不同,Websocket允许服务器自主地向客户端发送数据。这种实时连接的能力使得Websocket在许多应用场景中得到了广泛的应用。
Websocket技术的优点之一是减少了网络延迟。在传统的HTTP请求-响应模型中,客户端必须不断地向服务器发送请求以获取更新的数据。这种不断的请求-响应循环会占用大量的带宽和处理能力。而Websocket的持久连接可以在服务器有新数据时立即向客户端发送,从而减少了网络延迟和服务器负载。
另一个优点是Websocket可以处理大量的并发连接。在传统的HTTP请求-响应模型中,每个请求都必须在服务器上进行处理,这可能会对服务器造成负载压力。但是,Websocket的持久连接可以在服务器上保持打开状态,从而减少了与每个连接相关的开销。这使得服务器可以处理大量的并发连接而不会降低性能。
Websocket还可以用于实时通信。例如,聊天应用程序可以使用Websocket来实现实时消息传递。在这种情况下,Websocket的持久连接可以在服务器上保持打开状态,以便客户端可以接收实时消息。这种实时通信的能力使得Websocket在许多应用程序中得到了广泛的应用。
总之,Websocket技术在现代Web应用程序中发挥着越来越重要的作用。它可以减少网络延迟和服务器负载,处理大量的并发连接,并提供实时通信能力。因此,如果您正在构建一个需要实时更新的Web应用程序,那么Websocket技术可能是您的理想选择。
封装类实现
import { WebSocketConfigOption } from './WebSocketConfigOption';export class ReconnectableWebSocket {private ws!: WebSocket; // ws实例private opt: WebSocketConfigOption; // ws配置项private lockReconnect: boolean = false; // 避免ws重复连接private isClosingWindow: boolean = false;private reconnectTimeout: any;private heartSendInterval: any;constructor(option: WebSocketConfigOption) {if (null === option.url || '' === option.url) {throw ('url不能为空');}this.opt = option;this.initWebSocket();}private initWebSocket() {if (null == this.opt.secWebSocketProtocol) {this.ws = new WebSocket(this.opt.url);} else if (this.opt.secWebSocketProtocol.length == 0) {this.ws = new WebSocket(this.opt.url);} else {this.ws = new WebSocket(this.opt.url, this.opt.secWebSocketProtocol);}this.initEventHandle();window.onbeforeunload = () => {this.isClosingWindow = true;this.ws.close(); // 当窗口关闭时,主动去关闭websocket连接。}}private initEventHandle() {this.ws.onclose = () => {console.log('ws连接关闭!' + this.opt.url);this.opt.onclose && this.opt.onclose();this.heartCheckStop();if (!this.isClosingWindow) {this.reconnect();}}this.ws.onerror = () => {console.log('ws连接错误!' + this.opt.url);this.opt.onerror && this.opt.onerror();this.heartCheckStop();if (!this.isClosingWindow) {this.reconnect();}}this.ws.onopen = () => {console.log('ws连接成功!' + this.opt.url);this.opt.onopen && this.opt.onopen();this.heartCheckStart();}this.ws.onmessage = (event: any) => {this.opt.onmessage && this.opt.onmessage(event);}}/** 重连 */private reconnect() {if (this.lockReconnect) {return;}this.lockReconnect = true;this.reconnectTimeout = setTimeout(() => {this.initWebSocket();this.lockReconnect = false;}, 2000);}/** 关闭重连 */private reconnectStop(): void {clearTimeout(this.reconnectTimeout);}/** 开启心跳包保持连接 */private heartCheckStart(): void {this.ws.send('heartCheck');this.heartSendInterval = setInterval(() => {this.ws.send('heartCheck');}, 5 * 60 * 1000);}/** 关闭心跳包 */private heartCheckStop(): void {clearInterval(this.heartSendInterval);}/** 主动关闭连接 */public close(): void {this.reconnectStop();this.heartCheckStop();this.isClosingWindow = true;this.ws.close();}}
配置类实现
export type WebSocketConfigOption = {url: string;secWebSocketProtocol?: Array<string>;onopen?: () => void;onmessage?: (msg: any) => void;onerror?: () => void;onclose?: () => void;}
应用示例
import { WebSocketConfigOption } from '../websocket/WebSocketConfigOption';
import { ReconnectableWebSocket } from '../websocket/ReconnectableWebSocket';
import { InnerMqService } from '../../rx/inner-mq.service';export class MapMessageConnection {private ws!: ReconnectableWebSocket;constructor(private path: string,private innerMqService: InnerMqService,) {this.connection();}/** 连接 */private connection(): void {let wsConfig: WebSocketConfigOption = {url: this.path,onopen: () => {},onerror: () => {},onmessage: (msg: any) => {if (msg.data && msg.data !== '') {let data = JSON.parse(msg.data);this.innerMqService.pub(data.title, data.content);}}}this.ws = new ReconnectableWebSocket(wsConfig);}/** 断开连接 */public disConnection(): void {this.ws.close();}}
import { InnerMqClient } from '../../rx/inner-mq.service';
import { SubmitService } from '../../service/submit.service';
import { MapBase } from '../../map/map-base';
import { CommonUtil } from '../../util/common-util';
import { MapPage } from '../../view/page/map/map.page';
import { MapDraw } from '../../map/draw/map-draw';
import { MapWrap } from '../../map/draw/map-wrap';
import { GeoUtil } from "../../map/geo-util";
import { Point } from "../../map/entity/Point";export class MapMessageProcessor {constructor(private mqClient: InnerMqClient,private submitService: SubmitService,private mapBase: MapBase,private mapPage: MapPage,) {/** 放大 */mqClient.sub('ZoomIn').subscribe((res) => {mapBase.zoomIn();});/** 缩小 */mqClient.sub('ZoomOut').subscribe((res) => {mapBase.zoomOut();});/** 拖动 */mqClient.sub('Pan').subscribe((res) => {mapBase.pan();});/** 显示网格 */mqClient.sub('GridSwitch').subscribe((res) => {let update;if (mapBase.getGridVisible()) {mapBase.closeGrid();update = false;} else {mapBase.showGrid();update = true;}let config = mapBase.getMapConfig();if (config) {config.grid = update;CommonUtil.setConfigCache(config);mapBase.setMapConfig(config);}});/** 切换图层源 */mqClient.sub('SwitchResource').subscribe((res) => {// 切换图层debuggerlet lastType = mapBase.getCurrentCoordinateType();mapBase.switchMapResource(res);let currentType = mapBase.getCurrentCoordinateType();// 保存设置let config = mapBase.getMapConfig();if (config) {config.layer = res;CommonUtil.setConfigCache(config);mapBase.setMapConfig(config);}// 检查坐标类型if (lastType != currentType) {if (lastType == 'wgs84' && currentType == 'gcj02') {mapBase.turnMapFeaturesFromWgs84ToGcj02();} else if (lastType == 'gcj02' && currentType == 'wgs84') {mapBase.turnMapFeaturesFromGcj02ToWgs84();}}// 回调setTimeout(() => {mapPage.updateShowInfo();});});/** 绘制类型切换 - */mqClient.sub('SwitchDrawType').subscribe((res) => {mapBase.setDrawType(res);});/** 绘制 - */mqClient.sub('OpenDraw').subscribe((res) => {mapBase.pan();mapBase.removeDrawedFeatures();mapBase.openDraw({drawEnd: () => {setTimeout(() => {mapBase.removeDrawInteraction();})},modifyEnd: () => {}});});/** 绘制指定多边形并定位 - */mqClient.sub('DrawPolygonAndPositioning').subscribe((res) => {mapBase.pan();mapBase.removeDrawedFeatures();let blocks = JSON.parse(res);for (let i = 0; i < blocks.length; i++) {let points: Array<Point> = [];for (let j = 0; j < blocks[i].length; j++) {let point = new Point(blocks[i][j].lng, blocks[i][j].lat);if (mapBase.getCurrentCoordinateType() == 'wgs84') {points.push(GeoUtil.gcj02_To_wgs84(point));} else {points.push(point);}}let feature = MapDraw.createPolygonFeature(points);MapWrap.addFeature(mapBase, mapBase.drawLayerName, feature);}mapBase.setFitviewFromDrawLayer();});/** fitview - */mqClient.sub('Fitview').subscribe((res) => {mapBase.setFitviewFromDrawLayer();});/** 删除绘制 - */mqClient.sub('RemoveDrawedShape').subscribe((res) => {mapBase.removeDrawedFeatures();});/** 提交区块下载 - */mqClient.sub('SubmitBlockDownload').subscribe((res) => {let data = {tileName: this.mapBase?.getCurrentXyzName(),mapType: CommonUtil.getMapType(this.mapBase?.getCurrentXyzName()),tileUrl: this.mapBase?.getCurrentXyzUrlResources(),points: this.mapBase?.getDrawedPoints(),};this.submitService.blockDownload(data).then((r) => {});});/** 提交世界下载 - */mqClient.sub('SubmitWorldDownload').subscribe((res) => {let data = {tileName: this.mapBase?.getCurrentXyzName(),mapType: CommonUtil.getMapType(this.mapBase?.getCurrentXyzName()),tileUrl: this.mapBase?.getCurrentXyzUrlResources()};this.submitService.worldDownload(data).then((r) => {});});}}

如果对您有帮助
感谢支持技术分享,请点赞支持:
技术合作交流qq:2401315930
相关文章:
前端实现websocket类封装
随着Web应用程序的发展,越来越多的人开始利用Websocket技术来构建实时应用程序。Websocket是一种在客户端和服务器之间建立持久连接的协议。这种协议可以在一个单独的连接上实现双向通信。与HTTP请求-响应模型不同,Websocket允许服务器自主地向客户端发送…...
鸿蒙开发中的一些小问题
这是我在学习鸿蒙开发中遇见的小问题 Q1:This custom component must have a build function. <etsLint>Q2:page_title is not translated into en_US(American English)Q3:Module "../CustomComponent/CustomButton" declar…...
OpenCV-12绘制图像
OpenCV提供了许多绘制图像的API,可以在图像上绘制各种图形,例如直线,矩形,圆,椭圆等图形。 一、画直线 利用API line(img, pt1, pt2, color, thickness, lineType, shift)可以绘制直线。 其中…...
“2023年的技术发展与个人成长:回顾与展望“
文章目录 每日一句正能量前言工作生活未来展望后记 每日一句正能量 凡事顺其自然,遇事处于泰然,得意之时淡然,失意之时坦然,艰辛曲折必然,历尽沧桑悟然。 前言 在这快速发展的信息时代,技术的进步和创新不…...
算法逆袭之路(1)
11.29 开始跟进算法题进度! 每天刷4题左右 ,一周之内一定要是统一类型 而且一定稍作总结, 了解他们的内在思路究竟是怎样的!! 12.24 一定要每天早中晚都要复习一下 早中午每段一两道, 而且一定要是同一个类型, 不然刷起来都没有意义 12.26/27: 斐波那契数 爬…...
2023.12.31每日一题
LeetCode每日一题 2023年的最后一题 1154.一年中的第几天 1154. 一年中的第几天 - 力扣(LeetCode) 描述 给你一个字符串 date ,按 YYYY-MM-DD 格式表示一个 现行公元纪年法 日期。返回该日期是当年的第几天。 示例 1: 输入&a…...
Flink实时电商数仓(八)
用户域登录各窗口汇总表 主要任务:从kafka页面日志主题读取数据,统计 七日回流用户:之前活跃的用户,有一段时间不活跃了,之后又开始活跃,称为回流用户当日独立用户数:同一个用户当天重复登录&a…...
Python Pymysql实现数据存储
什么是 PyMySQL? PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一个库,Python2 中则使用mysqldb。 PyMySQL 遵循 Python 数据库 API v2.0 规范,并包含了 pure-Python MySQL 客户端库。 PyMySQL 安装 在使用 PyMySQL 之前…...
软件测试/测试开发丨Python 常用第三方库 pymysql
pymysql 概述 Python 的数据库接口标准是 Python DB-APIPyMySQL 是从 Python 连接到 MySQL 数据库服务器的接口PyMySQL 的目标是成为 MySQLdb 的替代品官方文档:pymysql.readthedocs.io/ pymysql 安装 使用 pip 安装使用 Pycharm 界面安装 pip install pymysqlp…...
第二节 linux操作系统安装与配置
一:Vmware虚拟机安装与使用 ①VMware是一个虚拟PC的软件,可以在现有的操作系统上虚拟出一个新的硬件环境,相当于模拟出一台新的PC ,以此来实现在一台机器上真正同时运行多个独立的操作系统。 ②VMware主要特点:…...
ChatGPT 对SEO的影响
ChatGPT 的兴起是否预示着 SEO 的终结? 一点也不。事实上,如果使用得当,它可以让你的 SEO 工作变得更加容易。 强调“正确使用时”。 你可以使用ChatGPT来帮助进行关键字研究的头脑风暴部分、重新措辞你的内容、生成架构标记等等。 但你不…...
光伏逆变器MPPT的作用、原理及算法
MPPT是逆变器非常核心的技术,MPPT电压在进行光伏电站设计时一项非常关键的参数。 一、什么是MPPT? (单块光伏组件的I-V、P-V曲线) 上图中,光伏组件的输出电压和电流遵循I-V曲线(绿色)、P-V曲线(蓝色),如果…...
一文详解pyspark常用算子与API
rdd.glom() 对rdd的数据进行嵌套,嵌套按照分区来进行 rdd sc.parallelize([1, 2, 3, 4, 5, 6, 7, 8, 9], 2)print(rdd.glom().collect()) 输出:[[1,2,3,4],[5,6,7,8,9]] 参考 PySpark基础入门(2):RDD及其常用算子…...
使用Rollup 搭建开发环境
1 什么是Rollup Rollup 是一个用于 JavaScript 的模块打包工具,它将小的代码片段编译成更大、更复杂的代码,例如库或应用程序。它使用 JavaScript 的 ES6 版本中包含的新标准化代码模块格式,而不是以前的 CommonJS 和 AMD 等特殊解决方案。(开…...
ubuntu:beyond compare 4 This license key has been revoked 解决办法
https://www.cnblogs.com/zhibei/p/12095431.html 错误如图所示: 解决办法: (1)先用find命令找到bcompare所在位置:sudo find /home/ -name *bcompare (2)进入 /home/whf/.config,删除/bco…...
华为交换机生成树STP配置案例
企业内部网络怎么防止网络出现环路?学会STP生成树技术就可以解决啦。 STP简介 在二层交换网络中,一旦存在环路就会造成报文在环路内不断循环和增生,产生广播风暴,从而占用所有的有效带宽,使网络变得无法正常通信。 在…...
Avalonia框架下实现热更新
在Avalonia框架下实现热更新(也称为动态加载或模块化更新),通常涉及程序集的动态加载与卸载,以及UI元素、视图模型或其他应用程序逻辑部分的实时替换。由于Avalonia本身是一个跨平台的GUI框架,并没有直接内置热更新机制…...
适用于各种危险区域的火焰识别摄像机,实时监测、火灾预防、安全监控,为安全保驾护航
火灾是一种极具破坏力的灾难,对人们的生命和财产造成了严重的威胁。为了更好地预防和防范火灾,火焰识别摄像机作为一种先进的监控设备,正逐渐受到人们的重视和应用。本文将介绍火焰识别摄像机在安全监控和火灾预防方面的全面应用方案。 一、火…...
react-router-dom5升级到6
前言 升级前版本为5.1.2 下载与运行 下载 npm install react-router-dom6运行 运行发现报错: 将node_modules删除,重新执行npm i即可 运行发现如下报错 这是因为之前有引用react-router-dom.min,v6中取消了该文件,所以未找到文件导致报错。…...
Linux调试工具—gdb
🎬慕斯主页:修仙—别有洞天 ♈️今日夜电波:HEART BEAT—YOASOBI 2:20━━━━━━️💟──────── 5:35 🔄 ◀️ ⏸ ▶️ ☰ …...
Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...
跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...
