有效封装一个 WebSocket 供全局使用
前言
在现代 Web 应用中,实时通信已经成为越来越重要的一部分。而 WebSocket 技术的出现,使得实时通信变得更加高效和便捷。
WebSocket 协议是一种基于 TCP 协议的双向通信协议,它能够在客户端和服务器之间建立起持久性的连接,从而实现实时通信。
在前端开发中,为了更好地利用 WebSocket 技术,我们通常会对其进行封装,以便于全局调用并根据自己的业务做不同的预处理。
本文将介绍如何有效封装一个 WebSocket 供全局使用,并根据自己的业务做不同的预处理,实现更方便的调用,减少重复代码。
具体实现思想
我们将基于 Web API 提供的 WebSocket
类,封装一个 Socket
类,该类将提供以下功能:
-
建立 WebSocket 连接,并支持发送
query
参数。 -
发送、接收消息,支持对
WebSocket
的事件进行监听。 -
断开 WebSocket 连接。
-
支持心跳检测。
-
可以根据业务需要,对发送和接收的消息进行预处理。
接下来我们从实际使用的角度解释一下上面的代码,首先我们暴露了一个 useSocket
函数,该函数接收一个 options
配置项参数,支持的参数有:
-
url
:要连接的 WebSocket URL; -
protocols
:一个协议字符串或者一个包含协议字符串的数组; -
query
:可以通过 URL 传递给后端的查询参数; -
greet
:心跳检测的打招呼信息; -
customBase
:自定义的baseURL
,否则默认使用环境变量中定义的env.VITE_APP_BASE_WS
。
在调用该函数后,我们首先会判断当前用户的浏览器是否支持 WebSocket
,如果不支持给予用户提示。
然后我们实例化了一个 EventMap
类的实例对象 dep
,你可以把它当作是一个依赖收集桶,当用户订阅了某个 WebSocket
事件时,我们将收集这个事件对应的回调作为依赖,在事件触发时,再通知该依赖,然后调用该事件对应的回调函数。
接下来我们定义了一个初始的重连次数记录值 reconnectCount
为 0,每当这个 WebSocket
重连时,该值会自增。
之后我们实例化了自己封装的 Socket
类,并传入了我们上面的三个参数。 在 Socket
类的构造函数 constructor
中,我们先取出配置项,把 query
内的参数拼接在 URL 上,然后使用 super
调用父类的构造函数进行建立 WebSocket
连接。
之后我们缓存了当前 Socket
实例化时的参数,再调用 initSocket()
方法去进行 WebSocket
事件的监听:
-
onopen:触发 dep 内 open 对应的回调函数并且打开心跳检测;
-
onclose:触发 dep 内 close 对应的回调函数并且对关闭的 code 码进行判断,如果是非正常关闭连接,将会进行重连,如果重连次数达到阈值,则通知给用户;
-
onerror:触发 dep 内 error 对应的回调函数;
-
onmessage:接收到服务端返回的数据,可以先根据自身业务做一些预处理,比如我就根据不同的数据类型进行了数据解析的预处理,之后再触发 dep 内 message 对应的回调函数并传入处理过后的数据。
我们也暴露了一些成员方法以供实例对象使用:
-
subscribe:订阅 WebSocket 事件,传入事件类型并须是 EventTypes 内的类型之一,第二个参数则是回调函数;
-
sendMessage`:同样的,我们在给服务端发送数据之前也可以根据自身业务做一些预处理,比如我将需要转成 JSON 的数据,在这里统一转换后再发送给服务端;
-
closeSocket:关闭 WebSocket 连接;
-
heartCheckStart:开始心跳检测,会创建一个定时器,在一定时间之后(默认是 55s)给服务端发送信息确认连接是否正常;
-
clearHeartCheck:清除心跳检测定时器(如果当前 WebSocket 连接已经关闭,则自动清除);
-
resetHeartCheck:重置心跳检测定时器。
实践
为了封装一个 WebSocket 类供全局使用,我们可以创建一个 Socket
类,提供必要的方法和功能。以下是一个简化的示例代码,展示了如何实现这个类:
// websocket.js
class Socket {
constructor(options) {
this.url = options.url;
this.protocols = options.protocols;
this.query = options.query;
this.greet = options.greet;
this.reconnectCount = 0;
this.initSocket();
}
initSocket() {
this.socket = new WebSocket(this.url);
this.socket.onopen = () => {
console.log(this.greet);
// ... 触发 open 事件的回调 ...
};
this.socket.onclose = (event) => {
// ... 处理关闭事件 ...
if (event.code !== 1000) {
// 非正常关闭
this.reconnect();
}
};
this.socket.onerror = (error) => {
// ... 处理错误事件 ...
};
this.socket.onmessage = (message) => {
// ... 处理接收到的消息 ...
};
}
reconnect() {
this.reconnectCount++;
// ... 实现重连逻辑 ...
}
sendMessage(data) {
this.socket.send(JSON.stringify(data));
}
closeSocket() {
this.socket.close();
}
heartCheckStart() {
// ... 实现心跳检测 ...
}
clearHeartCheck() {
// ... 清除心跳检测定时器 ...
}
resetHeartCheck() {
// ... 重置心跳检测定时器 ...
}
}
// 导出 Socket 类
export default Socket;
说明
-
构造函数:接收配置选项并初始化 WebSocket 连接。
-
事件处理:处理
onopen
、onclose
、onerror
和onmessage
事件。 -
重连机制:在连接关闭时,如果不是正常关闭,则尝试重连。
-
消息发送:提供
sendMessage
方法以发送消息。 -
心跳检测:提供心跳检测相关的方法。
你可以根据具体需求进一步扩展和修改这个类。