提示:记录工作中遇到的需求及解决办法
前言
前端通过WebSocket的单例模式实现实时通信效果
提示:以下是本篇文章正文内容,下面案例可供参考
一、代码
export default class SocketService {
/**
* 单例实例
*/
static instance = null;
static get Instance() {
if (!this.instance) {
this.instance = new SocketService();
}
return this.instance;
}
// 连接状态标记
isConnected = false;
// 重试计数器
reconnectCount = 0;
// 最大重连次数
maxReconnect = 5;
// 重连延迟 (毫秒)
reconnectDelay = 3000;
// WebSocket 实例
ws = null;
// 消息回调函数映射表
callbacks = new Map();
/**
* 初始化 WebSocket 连接
* @param {string} url - WebSocket 服务器地址
*/
connect(url) {
if (this.ws) {
this.disconnect();
}
this.ws = new WebSocket(url);
// 连接成功
this.ws.onopen = () => {
this.isConnected = true;
this.reconnectCount = 0;
console.log("WebSocket connected");
};
// 接收消息
this.ws.onmessage = (msg) => {
try {
const parsed = JSON.parse(msg.data);
const { event, data } = parsed;
// 触发对应事件回调
if (this.callbacks.has(event)) {
this.callbacks.get(event).forEach(cb => cb(data));
}
} catch (e) {
console.error("Message parsing failed", e);
}
};
// 连接关闭
this.ws.onclose = () => {
this.isConnected = false;
console.log("WebSocket disconnected");
// 自动重连逻辑
if (this.reconnectCount < this.maxReconnect) {
setTimeout(() => {
console.log(`Reconnecting... (${this.reconnectCount + 1}/${this.maxReconnect})`);
this.reconnectCount++;
this.connect(url);
}, this.reconnectDelay);
}
};
// 错误处理
this.ws.onerror = (err) => {
console.error("WebSocket error:", err);
this.ws.close();
};
}
/**
* 断开 WebSocket 连接
*/
disconnect() {
if (this.ws) {
this.ws.close();
this.ws = null;
this.isConnected = false;
}
}
/**
* 注册事件监听器
* @param {string} event - 事件名称
* @param {Function} callback - 回调函数
*/
on(event, callback) {
if (!this.callbacks.has(event)) {
this.callbacks.set(event, []);
}
this.callbacks.get(event).push(callback);
}
/**
* 发送消息
* @param {string} event - 事件类型
* @param {Object} data - 发送数据
*/
send(event, data) {
if (this.isConnected) {
const payload = JSON.stringify({ event, data });
this.ws.send(payload);
} else {
console.error("Cannot send message - WebSocket not connected");
}
}
/**
* 移除事件监听器
* @param {string} event - 事件名称
* @param {Function} callback - 要移除的回调函数
*/
off(event, callback) {
if (this.callbacks.has(event)) {
const callbacks = this.callbacks.get(event).filter(cb => cb !== callback);
this.callbacks.set(event, callbacks);
}
}
}
// 使用示例:
// const socket = SocketService.Instance;
// socket.connect("wss://api.example.com");
// socket.on("message", (data) => console.log("Received:", data));
// socket.send("update", { value: 42 });
二、功能说明
- 单例模式:
- 通过静态属性 instance 和静态方法 get Instance() 确保全局只有一个实例
- 首次调用 SocketService.Instance 时自动创建实例
- 核心功能:
- connect(url):建立 WebSocket 连接
- disconnect():主动断开连接
- on(event, callback):注册事件监听器
- off(event, callback):移除事件监听器
- send(event, data):发送结构化数据
- 自动重连机制:
- 连接断开时自动尝试重连(最多 5 次)
- 每次重连间隔 3 秒
- 连接成功后重置重连计数器
- 消息协议:
- 使用 JSON 格式:{ event: ‘事件名’, data: … }
- 自动解析消息并触发对应事件回调
三、使用场景
// 在应用初始化时建立连接
const socket = SocketService.Instance;
socket.connect("wss://api.example.com/ws");
// 监听服务器消息
socket.on("chatMessage", (msg) => {
console.log("New message:", msg);
});
// 发送数据
document.getElementById("sendBtn").addEventListener("click", () => {
socket.send("userAction", { type: "click", count: 5 });
});
// 组件卸载时移除监听
const handler = (data) => { /* ... */ };
socket.on("update", handler);
// 需要时移除特定监听器
socket.off("update", handler);
此实现提供了完整的 WebSocket 连接管理,包括自动重连、事件订阅/发布机制,并严格遵循单例模式确保全局状态一致性。