GlobalWebsoket.js 封装配置分析

news2024/11/17 21:22:25

GlobalWebsoket.js 封装配置分析

  • 前言
  • 一、 封装好的 `GlobalWebsoket.js `
    • 1. `GlobalWebsoket.js `
  • 二、`GlobalWebsoket.js` 代码分析
    • 1.`GlobalWebsoket.js ` import 分析
    • 2.`GlobalWebsoket.js ` 整体分析
    • 3. `initWebSoket()`
    • 3. `getWebsoket`
      • 4.` sendSocketMessage`
  • 三、`GlobalWebsoket.js` 使用分析


前言

由于项目业务逻辑需要,此次前端界面需要接收后端服务器 WebSoket 实时传输的数据,并在页面当中显示实时数据
项目中已经用 js 封装好了能用的 GlobalWebsoket.js


一、 封装好的 GlobalWebsoket.js

代码如下

1. GlobalWebsoket.js

// GlobalWebsoket.js
import store from '@/store/index.js';
import Config from '@/core/config' // 引入 cofig ,Config.js 当中配置的是 url 地址
import {
	Observable
} from "rxjs";

// 后端api地址
const wsHost = Config.get('wsUrl')
let ws;
let count = 0;
var subs = {};
let timer = {};
const MAX_RETRIES = 2000;
let trySendCount = 0;
let tempQueue = [];
let socketOpen = false;
const initWebSocket = () => {
	let token = store.state.token ? store.state.token : store.getters.token;
	const wsUrl = `${wsHost}/messaging/${token}?:X_Access_Token=${token}`;
	try {
		//微信websocket最大并发不能超过5个
		//https://developers.weixin.qq.com/miniprogram/dev/framework/ability/network.html

		if (count > 0) {
			return ws;
		}
		clearInterval(timer);
		ws = uni.connectSocket({
			url: wsUrl,
			complete: () => {}
		});
		count += 1;
		uni.onSocketClose(function() {
			socketOpen = false;
			ws = undefined;
			setTimeout(initWebSocket, 5000 * count);
		});
		uni.onSocketOpen(function() {
			socketOpen = true;
		});
		uni.onSocketMessage(function(msg) {
			var data = JSON.parse(msg.data);
			if (data.type === 'error') {
				uni.showToast({
					title: data.message,
					icon: "none",
					duration: 3500
				})
			}
			if (subs[data.requestId]) {
				if (data.type === 'complete') {
					subs[data.requestId].forEach(function(element) {
						element.complete();
					});;
				} else if (data.type === 'result') {
					subs[data.requestId].forEach(function(element) {
						element.next(data);
					});;
				}
			}
		});
	} catch (error) {
		setTimeout(initWebSocket, 5000 * count);
	}

	timer = setInterval(function() {
		try {
			ws && ws.readyState === 1 ? sendSocketMessage(JSON.stringify({
				"type": "ping"
			})) : 0;
		} catch (error) {
			console.error(error, '发送心跳错误');
		}
		//同时判断
		if (tempQueue.length > 0 && ws && ws.readyState === 1) {
			sendSocketMessage(tempQueue[0], 1);
		}
	}, 2000);
	return ws;
};

//flag,是否处理tempQueue中的数据,如果发送失败,则不会重新加入,发送成功,则去除
function sendSocketMessage(msg, flag) {
	if (socketOpen) {
		uni.sendSocketMessage({
			data: msg
		});
		if (flag === 1) {
			tempQueue.splice(0, 1);
		}
	} else {
		if (flag != 1) {
			tempQueue.push(msg);
		}
	}
}


const getWebsocket = (id, topic, parameter) => {
	return Observable.create(function(observer) {
		if (!subs[id]) {
			subs[id] = [];
		}
		subs[id].push({
			next: function(val) {
				observer.next(val);
			},
			complete: function() {
				observer.complete();
			}
		});
		var msg = JSON.stringify({
			id: id,
			topic: topic,
			parameter: parameter,
			type: 'sub'
		});
		var thisWs = initWebSocket();
		if (thisWs) {
			try {
				sendSocketMessage(msg);
			} catch (error) {
				initWebSocket();
				uni.showToast({
					title: 'websocket服务连接失败',
					icon: "none",
					duration: 3500
				})
			}
		} else {
			tempQueue.push(msg);
			ws = undefined
			count = 0
			initWebSocket();
		}
		return function() {
			var unsub = JSON.stringify({
				id: id,
				type: "unsub"
			});
			delete subs[id];
			if (thisWs) {
				sendSocketMessage(unsub)
			}
		};
	});
};
exports.getWebsocket = getWebsocket;

二、GlobalWebsoket.js 代码分析

1.GlobalWebsoket.js import 分析

import store from '@/store/index.js'; // vueX 做状态管理的
import Config from '@/core/config' // 引入 cofig ,Config.js 当中配置的是 url 地址
import {
	Observable
} from "rxjs";

Config 的地址是从 config.js 中来的
在这里插入图片描述

RxJS 是一个库,它通过使用 observable 序列来编写异步和基于事件的程序。它提供了一个核心类型 Observable,附属类型 (Observer、 Schedulers、 Subjects) 和受 [Array#extras] 启发的操作符 (map、filter、reduce、every, 等等),这些数组操作符可以把异步事件作为集合来处理。 可以把 RxJS 当做是用来处理事件的 Lodash 。

2.GlobalWebsoket.js 整体分析

GlobalWebsoket.js 文件导出了getWebsocket,这是一个函数

import store from '@/store/index.js';
import Config from '@/core/config'
import {
	Observable
} from "rxjs";

// 后端api地址
// 这里通过 Config 获取需要连接 websoket 的地址
const wsHost = Config.get('wsUrl')
let ws;
let count = 0;
var subs = {};
let timer = {};
const MAX_RETRIES = 2000;
let trySendCount = 0;
let tempQueue = [];
let socketOpen = false;


exports.getWebsocket = getWebsocket;

3. initWebSoket()

const initWebSocket = () => {
	// 先获取 token 
	let token = store.state.token ? store.state.token : store.getters.token;
	// 这里是 websoket 的 url 地址
	// ${wsHost} 是 通过 Config 获取需要连接 websoket 的地址
	// ${token} 是 token 信息
	const wsUrl = `${wsHost}/messaging/${token}?:X_Access_Token=${token}`;
	try {
		//微信websocket最大并发不能超过5个
		//https://developers.weixin.qq.com/miniprogram/dev/framework/ability/network.html

		// 如果连接数量大于 0 
		if (count > 0) {
			// 这里就返回当前连接
			return ws;
		}
		// 执行到这里说明连接数为 0 ,以下代码为创建新的 websoket 的连接
		clearInterval(timer);
		
		// 调用 uni.connectSocket 来创建连接
		ws = uni.connectSocket({
			url: wsUrl,
			complete: () => {}
		});
		count += 1;
		
		// 关闭连接的回调函数
		uni.onSocketClose(function() {
			socketOpen = false;
			ws = undefined;
			setTimeout(initWebSocket, 5000 * count);
		});
		
		// 连接打开的回调函数
		uni.onSocketOpen(function() {
			socketOpen = true;
		});
		
		// 当向 websoket 发送信息时的回调函数
		uni.onSocketMessage(function(msg) {
			var data = JSON.parse(msg.data);
			if (data.type === 'error') {
				uni.showToast({
					title: data.message,
					icon: "none",
					duration: 3500
				})
			}
			if (subs[data.requestId]) {
				if (data.type === 'complete') {
					subs[data.requestId].forEach(function(element) {
						element.complete();
					});;
				} else if (data.type === 'result') {
					subs[data.requestId].forEach(function(element) {
						element.next(data);
					});;
				}
			}
		});
	} catch (error) {
		setTimeout(initWebSocket, 5000 * count);
	}

	// 设置定时器,每 2 秒执行一次,发送一次 'ping'
	timer = setInterval(function() {
		try {
			ws && ws.readyState === 1 ? sendSocketMessage(JSON.stringify({
				"type": "ping"
			})) : 0;
		} catch (error) {
			console.error(error, '发送心跳错误');
		}
		//同时判断
		if (tempQueue.length > 0 && ws && ws.readyState === 1) {
			sendSocketMessage(tempQueue[0], 1);
		}
	}, 2000);
	// 返回新建的 ws
	return ws;
};

3. getWebsoket

const getWebsocket = (id, topic, parameter) => { 
	// 根据传递的 id, 处理 id, 获取需要监听的内容
	return Observable.create(function(observer) {
		if (!subs[id]) {
			subs[id] = [];
		}
		subs[id].push({ // 所有需要监听的内容 push 到 subs[] 数组当中
			next: function(val) {
				observer.next(val);
			},
			complete: function() {
				observer.complete();
			}
		});
	// 根据传参的 id,topic,parameter ,讲需要发送的监听的内容封装到 msg 对象中
		var msg = JSON.stringify({
			id: id,
			topic: topic,
			parameter: parameter,
			type: 'sub'
		});
		// 调用 initWebSoket,初始化 websocket,在 initWebSoket 当中发起连接
		var thisWs = initWebSocket();
		if (thisWs) { // 如果连接成功
			try {
				sendSocketMessage(msg); // 发送需要 websoket 绑定监听的 msg(上面封装好了)
			} catch (error) { // 如果发送失败,再次发起连接
				initWebSocket();
				uni.showToast({
					title: 'websocket服务连接失败',
					icon: "none",
					duration: 3500
				})
			}
		} else { // 如果没有连接成功
			tempQueue.push(msg); // 临时队列中先把 msg 存起来
			ws = undefined // 断掉当前的连接
			count = 0 // 并把连接数设为 0
			initWebSocket(); // 再次初始化 websoket
		}
		return function() {  // 这里是解绑的时候会执行的 (remove)
			var unsub = JSON.stringify({  
				id: id,
				type: "unsub"
			});
			delete subs[id];
			if (thisWs) {
				sendSocketMessage(unsub)
			}
		};
	});
};

4. sendSocketMessage


// 发送 soket 信息
//flag,是否处理tempQueue中的数据,如果发送失败,则不会重新加入,发送成功,则去除
function sendSocketMessage(msg, flag) {
	// 如果当前的 websoket 是打开的
	if (socketOpen) {
		// 向 websoket 发送消息
		uni.sendSocketMessage({
			data: msg
		});
		if (flag === 1) {
			tempQueue.splice(0, 1);
		}
	} else {
		if (flag != 1) {
			tempQueue.push(msg);
		}
	}
}


三、GlobalWebsoket.js 使用分析

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

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

相关文章

[附源码]Python计算机毕业设计大学生社团管理系统

项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等等。 环境需要 1.运行环境:最好是python3.7.7,…

大数据下一代变革之必研究数据湖技术Hudi原理实战双管齐下-中

文章目录核心原理数据写写操作UPSERT写流程INSERT写流程INSERT OVERWRIT写流程Key 生成策略删除策略写流程归纳数据读集成Spark使用环境准备spark-shell使用启动插入数据查询数据更新数据时间旅行查询增量查询指定时间点查询删除数据覆盖数据spark-sql使用启动创建表插入数据时…

状态压缩dp整理

目录蒙德里安的梦想详细解释Code最短Hamilton路径详细解释Code蒙德里安的梦想 求把 NMNMNM 的棋盘分割成若干个 121212 的长方形,有多少种方案。 例如当 N2,M4N2,M4N2,M4 时,共有 555 种方案。当 N2,M3N2…

语音合成技术入门之Tacotron

语音合成TTS 学习李宏毅课程。 输入文字,输出语音。 端到端之前TTS 18世纪就有,能找到demo的是1939年VODER。 就像电子琴一样,用手控制发出不同声音。 到1960年,IBM计算机能合成出歌唱声。 波形拼接 过去最常用的商用语音合…

策略验证_指标买点分析技法_运用MACD确定最佳买点

写在前面: 1. 本文中提到的“股票策略校验工具”的具体使用操作请查看该博文; 2. 文中知识内容来自书籍《同花顺炒股软件从入门到精通》 3. 本系列文章是用来学习技法,文中所得内容都仅仅只是作为演示功能使用 目录 解说 策略代码 结果 解…

【node.js】第六章 初识express

目录 1. express简介 1.1 express的概念 1.2 express的作用 2. express的使用 2.1 使用express创建Web服务器 2.2 监听GET/POST请求 2.3 获取URL的请求参数 3. 托管静态资源 3.1 express.static 3.2 托管多个静态资源 3.3 挂载路径前缀 4. nodemon 1. express…

Docker镜像操作、容器操作、数据卷及挂载数据卷

目录 一、镜像操作 案例:从DockerHub中拉取一个nginx镜像并查看 案例:利用docker save将nginx镜像导出磁盘,然后再通过load加载回来 二、容器操作 案例:创建运行一个Nginx容器 案例:创建并进入redis容器&#xf…

随笔记录-看nacos源码

Import注解 Import注解可以导入一些配置类,也就是创建一些指定对象。 使用Import导入普通类 项目结构中,import-consumer和import-provider都是同层级的module,import-consumer的pom文件中有引用import-provider的依赖; import…

baby_web (攻防世界)

前言: 这篇文章还是是为了帮助一些 像我这样的菜鸟 找到简单的题解 题目描述 进入网址 解题工具: 一个有F12的键盘 问题解析: 题目说想想初始页面是哪个 一般都是index.php 然后如题分析即可 科普时间叒到 HTTP状态码 (英语:HTTP Status Code…

从零开始操作系统-08:计时器

这一节主要主要是计时器。 所需要的文件在Github:https://github.com/yongkangluo/Ubuntu20.04OS/tree/main/Files/Lec7-ExternalInterrupt 计时器: 可编程间隔计时器:PIT(Programmalbe Interval Timer)8254 使用A…

Windows下文本生成图像AI画图尝鲜体验

工具库 transformers 的开源方 Hugging Face 发布了一个专注于 diffuser 模型的开源库,我们可以基于它,仅仅通过几行代码就开始生成自己的艺术作画。不过这个 diffuser 库是一个基础实现版本,训练和学习的数据也没有 OpenAI 的 DALL-E2、谷歌…

学习docker记录(三)

使用volume 创建一个数据卷 docker volume create test-first-volume创建完之后,可以在 /var/lib/docker/volumes/ 目录下看见新建了一个 test-first-volume文件夹 在Dockerfile中 volume的指定的目录是: /www/wwwroot/pictureManager/deploy原本以为…

三步教你快速入手一个新产品的测试

初入一家公司,当一个全新的产品摆在你的面前,你会如何快速入手呢? 虽说实践是熟悉系统的第一要素,但我们需要静静思考一下。 我是谁:QA 我在哪:产品组 我要做什么:保质量 有多少来熟悉&…

LeetCode 320 周赛

总结 本场周赛太拉跨了!T1做完后,T2一直被卡住,还好后面暂时跳过了T2去做T3,T3做完后又回过头来继续调试T2。在最后10分钟调过了(虽然后来看运行时长达到了1400ms(差点就过不了))。 …

vue3 斗兽棋游戏

近来掘金举办前端比赛,所以写了一个小游戏参加,而且熟悉一下vue3,写了一下游戏,思来想去就写了一个斗兽棋游戏。 欢迎去给我加油 点赞评论收藏 ,试玩地址 游戏地址 童年斗兽棋 - 码上掘金 https://code.juejin.cn/pen/716…

四川水泥杂志四川水泥杂志社四川水泥编辑部2022年第11期目录

水泥与混凝土 外加剂含固量对混凝土性能影响的分析 金世鑫; 1-4 《四川水泥》投稿:cnqikantg126.com 粉煤灰在干混砂浆中的应用研究 方光旭;古再努尔依明;杨博;陈南希;张琰琦; 5-7 浅析透光混凝土在建筑空间中的应用 李嘉;李嘉鑫; 8-10 研究与探讨…

c++ 智能指针 shared_ptr

C 智能指针 shared_ptr 详解与示例_码农小明的博客-CSDN博客_shared_ptr 一、简介 shared_ptr 是c11的智能类,可以在任何地方都不使用的时候自动删除和相关指针,从而彻底消除内存泄漏和指针悬空的问题。 她遵循共享所有权,即不同的shared_pt…

CVPR‘15 Joint action recognition and pose estimation from video

任务:action recognition and pose estimation 思路:对动作和姿态进行统一建模,将动作分成姿态,再将姿态分成part,学习三种level特征,通过动态规划有效的推断动作标签和姿态。 方法:统一建模…

通俗理解计算机操作系统的作用

“操作系统”,简称“OS”,是一个包含多个部分和多个目标的大型程序。 它的第一项工作是在你第一次打开计算机时启动并运行计算机。它的另一项工作是启动和结束应用程序,并给每个程序一个运行时间。它是那台计算机上所有其他程序的“老大”。当…

【App自动化测试】(一)Appium和移动端自动化

目录1. 目前mobile自动化解决方案1.1 iOS和Android 测试工具1.2 自动化工具的选择1.3 选择自动化工具的考虑因素2. Appium介绍2.1 Appium介绍2.2 多架构支持2.3 推荐Appium的理由2.4. Appium框架介绍2.4.1 Appium引擎列表2.4.2 Appium设计理念前言: 本文为在霍格沃兹…