1. 为什么你的Vue2项目需要一个“活”的WebSocket?
最近在做一个后台管理系统,里面有个需求是要实时弹窗显示服务器的告警信息。一开始我图省事,直接写了个定时器,每隔5秒就发个HTTP请求去问后端:“老哥,有新的告警吗?” 结果没两天,后端同事就来找我了,说我这请求太频繁,服务器压力有点大。而且更尴尬的是,有时候告警都发生十几秒了,我这边才轮询到,用户看到的根本不是“实时”告警。
这其实就是典型的“用牛刀杀鸡,结果发现刀不够快”。HTTP协议本身是“请求-响应”模式,就像你打电话问朋友“在干嘛”,他回答你,然后电话就挂了。你想知道他的最新动态,只能再打过去。而WebSocket不一样,它更像你们俩开了一个持续的电话会议,一旦接通,任何一方都可以随时说话,信息是双向、实时流动的。对于聊天、实时通知、监控数据推送这种场景,WebSocket才是那把趁手的“瑞士军刀”。
在Vue2项目里,尤其是中大型项目,直接把 new WebSocket() 写在组件里是下下策。我见过不少新手朋友这么干,结果就是:
- 连接管理混乱:页面跳转时,忘记关闭旧连接,导致内存泄漏和后台一堆无用连接。
- 状态分散:数据收回来了,有的存在组件的
data里,有的用EventBus乱发,后期维护像在走迷宫。 - 重连逻辑缺失:网络一波动,连接断了就再也连不上了,用户只能刷新页面。
所以,咱们今天要聊的,不是简单地调用几个WebSocket API,而是如何在Vue2的工程化环境下,系统化地解决实时通信问题。核心就两点:一是把WebSocket操作封装成一个可靠、易用的工具;二是把通信产生的数据,优雅地融入Vuex状态管理流。这样,无论你的项目是全局告警、在线协同编辑还是实时数据大屏,这套架构都能让你稳如老狗。
2. 第一步:打造你的专属WebSocket工具类
直接裸用 WebSocket API,就像开手动挡的车,虽然直接,但在复杂的城市路况(项目)里容易手忙脚乱。我们的目标是把它升级成“自动挡”,甚至带“自动驾驶辅助”。
2.1 基础连接封装:不止是 new WebSocket()
原始文章里给出了一个很基础的 websocket.js 工具函数,它解决了浏览器兼容性和Promise化的问题,这是个很好的起点。但在实战中,这远远不够。我们需要一个更健壮、功能更全面的类。
// utils/websocket.js
class MyWebSocket {
constructor(url, options = {}) {
// 核心配置
this.url = url;
this.ws = null;
this.reconnectCount = 0; // 当前重连次数
this.maxReconnectAttempts = options.maxReconnectAttempts || 5; // 最大重连次数
this.reconnectInterval = options.reconnectInterval || 3000; // 重连间隔(ms)
this.heartbeatInterval = options.heartbeatInterval || 30000; // 心跳间隔(ms)
this.heartbeatTimer = null;
this.reconnectTimer = null;
// 事件回调映射
this.eventHandlers = {
open: [],
message: [],
error: [],
close: []
};
this._init();
}
// 初始化连接
_init() {
if (!('WebSocket' in window)) {
console.error('您的浏览器不支持 WebSocket!');
return;
}
try {
this.ws = new WebSocket(this.url);
this._bindEvents();
} catch (error) {
console.error('WebSocket 连接创建失败:', error);
this._handleError(error);
}
}
// 绑定原生事件
_bindEvents() {
this.ws.onopen = (event) => {
console.log('WebSocket 连接成功');
this.reconnectCount = 0; // 连接成功,重置重连计数
this._startHeartbeat(); // 开启心跳
this._emit('open', event);
};
this.ws.onmessage = (event) => {
// 这里可以统一处理消息,比如判断是否是心跳回应
const data = event.data;
if (data === 'pong') {
console.log('收到服务器心跳回应');
return; // 心跳包不向上传递
}
this._emit('message', event);
};
this.ws.onerror = (event) => {
console.error('WebSocket 发生错误');
this._emit('error', event);
};
this.ws.onclose = (event) => {
console.warn(`WebSocket 连接关闭,代码: ${event.code}`);
this._stopHeartbeat();
this._emit('close', event);
// 非正常关闭,尝试重连
if (event.code !== 1000
375



被折叠的 条评论
为什么被折叠?



