前端实现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 🔄 ◀️ ⏸ ▶️ ☰ …...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
