【Vue实战】WebSocket消息监听实战详解
前言
哈喽!CSDN!
很久以前有位好朋友就建议来CSDN做一些笔记,直到最近又被提醒了一次,这次终于想起来了,
好习惯还是需要一个好的开始 ╭(●`∀´●)╯,感谢这位好朋友让我拥有这个好习惯 ╭(′▽`)╭(′▽`)╯
这位好朋友的博客链接如下:
项目场景:
由于业务需求,此次前端界面须接收来自后端服务器WebSocket实时推送的消息来实现进度显示。
WebSocket.js
JS封装WebSocket,代码如下:
let Socket = ''
let setIntervalWesocketPush = null
//缓存ip
let ip = ''
/**
* 建立websocket连接
* @param {string} url ws地址
*/
export const createSocket = url => {
Socket && Socket.close()
if (!Socket) {
console.log('建立websocket连接')
//建立连接的时候缓存服务端ip以便于其他方法调用
ip = url;
Socket = new WebSocket(url)
//发送心跳
Socket.onopen = onopenWS
//接收消息
Socket.onmessage = onmessageWS
//连接失败重连
Socket.onerror = onerrorWS
//断开重连
Socket.onclose = oncloseWS
} else {
console.log('websocket已连接')
}
}
/**打开WS之后发送心跳 */
const onopenWS = () => {
sendPing()
}
/**连接失败重连 */
const onerrorWS = () => {
Socket.close()
clearInterval(setIntervalWesocketPush)
console.log('连接失败重连中')
if (Socket.readyState !== 3) {
Socket = null
createSocket(ip)
}
}
/**WS数据接收统一处理 */
const onmessageWS = e => {
window.dispatchEvent(new CustomEvent('onmessageWS', {
detail: {
data: e.data
}
}))
}
/**
* 发送数据但连接未建立时进行处理等待重发
* @param {any} message 需要发送的数据
*/
const connecting = message => {
setTimeout(() => {
if (Socket.readyState === 0) {
connecting(message)
} else {
Socket.send(JSON.stringify(message))
}
}, 1000)
}
/**
* 发送数据
* @param {any} message 需要发送的数据
*/
export const sendWSPush = message => {
if (Socket !== null && Socket.readyState === 3) {
Socket.close()
createSocket(ip)
} else if (Socket.readyState === 1) {
Socket.send(JSON.stringify(message))
} else if (Socket.readyState === 0) {
connecting(message)
}
}
/**断开重连 */
const oncloseWS = () => {
clearInterval(setIntervalWesocketPush)
console.log('websocket已断开....正在尝试重连')
if (Socket.readyState !== 2) {
Socket = null
createSocket(ip)
}
}
/**发送心跳
* @param {number} time 心跳间隔毫秒 默认5000
* @param {string} ping 心跳名称 默认字符串ping
*/
export const sendPing = (time = 5000, ping = 'ping') => {
clearInterval(setIntervalWesocketPush)
Socket.send(ping)
setIntervalWesocketPush = setInterval(() => {
Socket.send(ping)
}, time)
}
getSocketData
监听并处理来自服务端WebSocket推送的消息。
data() {
return {
//声明一个变量来注册监听事件
getSocketData: null,
url: 'ws://localhost/webSocket'
}
},
methods:{
init() {
//页面初始化的时候开启WebSocket
createSocket(this.url);
// 创建接收消息函数
this.getSocketData = e => {
const data = e && e.detail.data
//这边编写处理服务端消息代码
}
//注册监听事件
window.addEventListener('onmessageWS', this.getSocketData)
}
},
mounted() {
this.init();
}
问题描述:
注册监听服务端WebSocket推送的消息后,刷新、关闭并重新打开页面的时候会遇到一个问题,客户端页面接收消息时会有重复的消息,同一条消息重复接收多次,导致多次弹窗、显示错误等问题。
原因分析:
开始问题排查:
- 检查服务端WebSocket消息推送代码逻辑,进行断点调试,没问题。
- 检查前端webSocket.js代码,console.log()进行打桩调试,没问题。
- 检查前端页面创建接收消息函数代码进行打桩调试,没问题。
- 通过Chrome控制台查看Event Listeners,发现问题所在。
如上图所示,onmessageWS同时有3个监听事件,所以当接收WebSocket消息触发的所有动作都会因此执行三遍。
解决方案:
在vue生命周期的destroyed阶段进行监听,详细代码如下:
destroyed() {
//移除监听器
window.removeEventListener('onmessageWS', this.getSocketData);
}
当页面销毁时,移除监听器,这样就不会导致重复监听。
总结:
本次排查此问题从后端到前端前后大概1小时左右时间,感觉时间有点久,看来技术还得和各位大佬多学学,以下找到篇写得不错的关于此次问题的博文,和大家分享一下。
1、添加监听事件(addEventListener)
语法:element.addEventListener(event, function, useCapture)
event:指定事件名(注意: 不要使用 “on” 前缀。 例如,使用 “click” ,而不是使用 “onclick”)
function:指定要事件触发时执行的函数(事件对象会作为第一个参数传入函数)
useCapture:指定事件是否在捕获或冒泡阶段执行,默认false(true - 事件句柄在捕获阶段执行,false-事件句柄在冒泡阶段执行)
mounted() {
//添加监听器
window.addEventListener("resize", this.setNavLeft);
},
methods: {
listenerFunction(e) {
document.addEventListener("scroll", this.handleScroll, true);
},
}
2、移除监听事件(removeEventListener)
语法:element.removeEventListener(event, function, useCapture)
注意:在vue中销毁事件监听,一定要在destroyed生命周期中执行,在 beforeDestroy到destroyed之间,执行组件事件拆卸,在beforeDestroy中执行事件销毁是成功不了的。
destroyed() {
//移除监听器
document.removeEventListener("scroll", this.handleScroll, true);
window.removeEventListener("resize", this.setNavLeft);
},
都看到这儿了,如果有帮到您的话,不妨来个一键三连吧!^_^