前端实现websocket类封装

news2024/11/16 11:29:36

随着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) => {
         // 切换图层
         debugger
         let 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1339261.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Flutter配置Android和IOS允许http访问

默认情况下&#xff0c;Android和IOS只支持对https的访问&#xff0c;如果需要访问不安全的连接&#xff0c;也就是http&#xff0c;需要做以下配置。 Android 在res目录下的xml目录中(如果不存在&#xff0c;先创建xml目录)&#xff0c;创建一个xml文件network_security_con…

八股文打卡day12——计算机网络(12)

面试题&#xff1a;HTTPS的工作原理&#xff1f;HTTPS是怎么建立连接的&#xff1f; 我的回答&#xff1a; 1.客户端向服务器发起请求&#xff0c;请求建立连接。 2.服务器收到请求之后&#xff0c;向客户端发送其SSL证书&#xff0c;这个证书包含服务器的公钥和一些其他信息…

Codeforces Round 917 (Div. 2)更新中...

A.Least Product(思维) 题意&#xff1a; 给出一个数组 a 1 , a 2 , . . . , a n a_1, a_2, ..., a_n a1​,a2​,...,an​&#xff0c;你可以进行若干次以下操作&#xff1a; 选择数组中的一个元素 a i a_i ai​&#xff0c;将这个数字修改为 0 ∼ a i 0 \sim a_i 0∼ai​之…

《Spring Cloud学习笔记:微服务保护Sentinel》

Review 解决了服务拆分之后的服务治理问题&#xff1a;Nacos解决了服务治理问题OpenFeign解决了服务之间的远程调用问题网关与前端进行交互&#xff0c;基于网关的过滤器解决了登录校验的问题 流量控制&#xff1a;避免因为突发流量而导致的服务宕机。 隔离和降级&#xff1a…

XIAO ESP32S3之物体检测加入视频流

一、前言 由于XIAO ESP32S3开发套件没有显示屏配件&#xff0c;因此加入http视频流功能&#xff0c;可通过浏览器请求ESP32S3上的视频流。 二、思路 1、XIAO ESP32S3启动后通过wifi连接到AP&#xff1b; 2、启动http服务器&#xff0c;注册get_mjpeg处理函数&#xff1b; 3…

判断电话号码是否重复-excel

有时候重复的数据不需要或者很烦人&#xff0c;就需要采取措施&#xff0c;希望以下的方法能帮到你。 1.判断是否重复 方法一&#xff1a; 1&#xff09;针对第一个单元格输入等号&#xff0c;以及公式countif(查找记录数的范围&#xff0c;需要查找的单元格&#xff09; 2…

Linux:不同计算机使用NFS共享资源

一&#xff0c;安装NFS文件系统 NFS即网络文件系统(network file system)&#xff0c;它允许网络中的计算机之间通过网络共享资源。目前&#xff0c;NFS只用于在Linux和UNIX主机间共享文件系统。 #使用mount命令可以将远程主机的文件系统 安装到 本地&#xff1a; #将远程主机…

2.3_3 进程互斥的硬件实现办法

2.3_3 进程互斥的硬件实现办法 1.中断屏蔽方法 利用“开/关中断指令”实现&#xff08;与原语的实现思想相同,即在某进程开始访问临界区到结束访问为止都不允许被中断,也就不能发生进程切换,因此也不可能发生两个同时访问临界区的情况&#xff09; 优点&#xff1a;简单、高效…

浏览器Post请求出现413 Request Entity Too Large (Nginx)

环境 操作系统 window server 2016 前端项目 Vue2 Nginx-1.25.3 一、错误信息 前端是vue项目&#xff0c;打包后部署在Nginx上&#xff0c;前端post请求出现Request Entity Too Large错误信息。 ​这种问题一般是请求实体太大&#xff08;包含参数&#xff0c;文件等&#xf…

是德科技E9304A功率传感器

是德科技E9304A二极管功率传感器测量频率范围为9 kHz至6 GHz的平均功率&#xff0c;功率范围为-60至20 dBm。该传感器非常适合甚低频(VLF)功率测量。E系列E9304A功率传感器有两个独立的测量路径&#xff0c;设计用于EPM系列功率计。功率计自动选择合适的功率电平路径。为了避免…

HTML制作暴雨特效

🎀效果展示 🎀代码展示 <body> <!-- partial:index.partial.html --> <canvas id="canvas-club">

c语言结构体(初阶)

1. 结构体的声明 1.1 结构体的基础知识 结构是一些值的集合&#xff0c;这些值被称为成员变量。结构的每个成员可以是不同类型的变量。 1.2 结构的声明 struct tag {member - list; }variable-list; 例&#xff1a;描述一个人的信息&#xff1a;名字电话性别身高 //声明的…

如何利用ChatGPT处理文本、论文写作、AI绘图、文献查阅、PPT编辑、编程等

无论是进行代码生成、错误调试还是解决编程难题&#xff0c;ChatGPT都能为您提供实用且高质量的建议和指导&#xff0c;提高编程效率和准确性。此外&#xff0c;ChatGPT是一位出色的合作伙伴&#xff0c;可以为您提供论文写作的支持。它可以为您提供论文结构指导、段落重组建议…

LabVIEW快速入门

参考&#xff1a; 知乎labview快捷键 https://www.zhihu.com/question/287709225github 上 LabVIEW教程 https://lv.qizhen.xyz/LabVIEW 参考书籍 链接&#xff1a;https://pan.baidu.com/s/1irc0iftM0Gg3GCN2cBHCKw?pwdy1mz 提取码&#xff1a;y1mz --来自百度网盘超级会员V…

.NET 使用Camunda快速入门

一.工作流介绍 1. 什么是工作流 工作流&#xff08;Workflow&#xff09;&#xff0c;是对工作流程及其各操作步骤之间业务规则的抽象、概括描述。 工作流将一套大的业务逻辑分解成业务逻辑段&#xff0c; 并统一控制这些业务逻辑段的执行条件&#xff0c;执行顺序以及相互通…

【双系统】Windows10+Ubuntu22.04安装全过程以及安装后的配置

文章目录 0 背景0.1 电脑配置0.2 电脑磁盘的初始情况 1 准备空闲的磁盘1.1 文件整理1.2 压缩卷和扩展卷的操作 2 准备系统启动盘3 设置电脑的模式&#xff08;未验证&#xff09;并进入Ubuntu安装4 安装Ubuntu5 Ubuntu的配置6 其他 0 背景 之前一直在虚拟机上使用Ubuntu系统&am…

CentOS 5/6/7 基于开源项目制作openssh 9.6p1 rpm包—— 筑梦之路

背景介绍 开源项目地址&#xff1a;https://github.com/boypt/openssh-rpms.git 该项目主要支持了centos 5 、6、7版本&#xff0c;针对使用了比较老的操作系统进行openssh安全加固&#xff0c;还是不错的项目&#xff0c;使用简单、一件制作&#xff0c;欢迎大家去支持作者。…

YOLOv5改进 | 主干篇 | 利用SENetV2改进网络结构 (全网首发改进)

一、本文介绍 本文给大家带来的改进机制是SENetV2&#xff0c;其是2023.11月的最新机制(所以大家想要发论文的可以在上面下点功夫)&#xff0c;其是一种通过调整卷积网络中的通道关系来提升性能的网络结构。SENet并不是一个独立的网络模型&#xff0c;而是一个可以和现有的任何…

电影“AI化”已成定局,华为、小米转战入局又将带来什么?

从华为、Pika、小米等联合打造电影工业化实验室、到Pika爆火&#xff0c;再到国内首部AI全流程制作《愚公移山》开机……业内频繁的新动态似乎都在预示着2023年国内电影开始加速进入新的制片阶段&#xff0c;国内AI电影热潮即将来袭。 此时以华为为首的底层技术科技企业加入赛…

openmediavault(OMV) (19)云相册(3)mt-photos

简介 MT Photos是一款为Nas用户量身打造的照片管理系统。通过AI技术,自动将您的照片整理、分类,包括但不限于时间、地点、人物、照片类型。可以在任何支持Docker的系统中运行它。详情可查看mtmt.tech官网,mt-photos是付费订阅使用的,也可以一次性付费永久使用,具体使用mt…