前端 WebSocket 实战:替代轮询的实时通信方案
引言
本文探讨前端 WebSocket 的应用。相比 HTTP 轮询,WebSocket 能提供更高效的实时数据获取方式。
为什么需要 WebSocket
轮询实现实时功能效率较低,频繁请求服务器会增加带宽消耗和延迟。
轮询示例
// 轮询获取数据
function startPolling() {
setInterval(async () => {
const response = await fetch('/api/messages');
const messages = await response.json();
updateMessages(messages);
}, 1000); // 每秒请求一次
}
技术点评:高频轮询会显著增加服务器负载,不适合高并发场景。
前端 WebSocket 的正确姿势
1. 基础 WebSocket 使用
// 封装 WebSocket 客户端
class WebSocketClient {
constructor(url) {
this.url = url;
this.ws = null;
this.reconnectAttempts = 0;
this.maxReconnectAttempts = 5;
this.listeners = new Map();
}
connect() {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => {
console.log('WebSocket 连接成功');
this.reconnectAttempts = 0;
this.emit('open');
};
this.ws.onmessage = (event) => {
const data = JSON.parse(event.data);
this.emit(data.type, data.payload);
};
this.ws.onclose = () => {
console.log('WebSocket 连接关闭');
this.emit('close');
this.reconnect();
};
this.ws.onerror = (error) => {
console.error('WebSocket 错误:', error);
this.emit('error', error);
};
}
send(type, payload) {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify({ type, payload }));
}
}
on(event, callback) {
if (!this.listeners.has(event)) {
this.listeners.set(event, []);
}
this.listeners.get(event).push(callback);
}
emit(event, data) {
if (this.listeners.has(event)) {
this.listeners.get(event).forEach(callback => callback(data));
}
}
reconnect() {
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++;
console.log(`尝试重连... (${this.reconnectAttempts}/${this.maxReconnectAttempts})`);
setTimeout(() => this.connect(), 3000);
}
}
disconnect() {
if (this.ws) {
this.ws.close();
}
}
}
// 使用示例
const ws = new WebSocketClient('wss://api.example.com/ws');
ws.on('open', () => {
console.log('连接成功');
});
ws.on('message', (data) => {
console.log('收到消息:', data);
});
ws.connect();
2. React 中使用 WebSocket
// React Hook 封装
import { useEffect, useRef, useState, useCallback } from 'react';
function useWebSocket(url) {
const [isConnected, setIsConnected] = useState(false);
const [messages, setMessages] = useState([]);
const ws = useRef(null);
useEffect(() => {
ws.current = new WebSocket(url);
ws.current.onopen = () => setIsConnected(true);
ws.current.onclose = () => setIsConnected(false);
ws.current.onmessage = (event) => {
const data = JSON.parse(event.data);
setMessages(prev => [...prev, data]);
};
return () => {
ws.current.close();
};
}, [url]);
const sendMessage = useCallback((message) => {
if (ws.current && ws.current. === .) {
ws..(.(message));
}
}, []);
{ isConnected, messages, sendMessage };
}
() {
{ isConnected, messages, sendMessage } = ();
[input, setInput] = ();
= () => {
({ : , : input });
();
};
(
);
}
3. 使用 Socket.io
// 引入 Socket.io 客户端
import { io } from 'socket.io-client';
const socket = io('https://api.example.com', {
transports: ['websocket'],
autoConnect: true,
reconnection: true,
reconnectionAttempts: 5,
reconnectionDelay: 3000
});
// 连接事件
socket.on('connect', () => {
console.log('连接成功,ID:', socket.id);
});
// 断开连接
socket.on('disconnect', () => {
console.log('连接断开');
});
// 监听消息
socket.on('message', (data) => {
console.log('收到消息:', data);
});
// 发送消息
socket.emit('chat message', { text: 'Hello' });
// 加入房间
socket.emit('join room', 'room-1');
实战技巧:WebSocket 指南
1. WebSocket 使用场景
- 实时聊天:即时通讯
- 实时数据:股票、比分更新
- 协同编辑:多人协作
- 在线游戏:实时对战
2. 最佳实践
- 重连机制:断线自动重连
- 心跳检测:保持连接活跃
- 消息确认:确保消息送达
- 错误处理:优雅处理异常
总结
WebSocket 是实时通信的标准协议。相比 HTTP 轮询,它建立了持久连接,降低了延迟和服务器压力。建议根据实际场景选择合适的实现方式。


