封装WebSocket消息推送,干翻Ajax轮询方式
前言
使用AJAX和WebSocket都可以实现消息推送,但它们在实现方式和适用场景上有所不同。本文将对这两种技术的实现进行简要说明,并介绍如何封装一个WebSocket消息推送管理器,替代传统的AJAX轮询方式。
AJAX 实现消息推送
轮询(Polling)
轮询是指客户端定期向服务器发送请求以检查是否有新消息。尽管简单易用,但频繁的无效请求会带来性能开销。
function pollForMessages() {
$.ajax({
url: '/messages',
method: 'GET',
success: function(data) {
console.log(data); // 处理接收到的消息
setTimeout(pollForMessages, 5000); // 每5秒轮询一次
},
error: function() {
setTimeout(pollForMessages, 10000); // 请求失败时等待更长时间后重试
}
});
}
// 开始轮询
pollForMessages();
长轮询(Long-Polling)
长轮询是轮询的改进版本,客户端发起请求后,服务器在有新消息时才会返回响应,否则保持连接。尽管能减少无效请求,但仍存在延迟问题。
WebSocket 实现消息推送
WebSocket是一种全双工的通信协议,允许服务器主动向客户端推送消息。相比AJAX的请求-响应模式,WebSocket的通信更为高效。
var socket = new WebSocket('ws://your-server-url');
socket.onopen = function(event) {
socket.send('Hello Server!');
};
socket.onmessage = function(event) {
console.log('Received:', event.data);
};
socket.onerror = function(error) {
console.error('WebSocket Error:', error);
};
socket.onclose = function(event) {
console.log('WebSocket is closed now.');
};
WebSocket 消息推送封装
概念类比
想象你是一个快递员,负责将消息包裹(WebSocket消息)送到不同的收件人(客户端)。你通过一辆智能快递车(WebSocket连接)传递消息,并记录每个收件人的信息。每次有新消息时,快递车会自动将包裹送达收件人,并在收到回复时立刻通知你。
WebSocketManager 设计思路
WebSocketMessenger负责管理和维护WebSocket连接,并通过封装实现对连接的控制、消息的发送和接收,以及重连机制。
WebSocketManager 类
class WebSocketManager {
constructor(url = null, userId = null, receiveMessageCallback = null) {
this.socket = null;
this.sendTimeObj = null;
this.reconnectTimeObj = null;
this.reconnectTimeDistance = 5000;
this.maxReconnectAttempts = 10;
this.reconnectAttempts = 0;
this.id = userId;
this.url = url;
this.receiveMessageCallback = receiveMessageCallback;
}
// 开启WebSocket连接
async start() {
if (this.url && this.id) {
this.connectWebSocket();
} else {
console.error('WebSocket errors: 请传入连接地址和用户id');
}
}
// 创建WebSocket连接
connectWebSocket() {
let id = `${this.id}-${Math.random()}`;
this.socket = new WebSocket(this.url, id);
this.socket.onopen = (event) => {
this.startSendServe();
};
this.socket.onmessage = (event) => {
this.receiveMessage(event);
};
this.socket.onclose = (event) => {
clearTimeout(this.sendTimeObj);
clearTimeout(this.reconnectTimeObj);
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++;
this.reconnectTimeObj = setTimeout(() => {
this.connectWebSocket();
}, this.reconnectTimeDistance);
} else {
this.reconnectAttempts = 0;
console.error('WebSocketManager errors: Max reconnect attempts reached.');
}
};
this.socket.onerror = (event) => {
console.error('WebSocketManager error:', event);
};
}
// 发送消息
sendMessage(message) {
if (this.socket.readyState === WebSocket.OPEN) {
this.socket.send(message);
} else {
console.error('WebSocketManager error: WebSocket connection is not open.');
}
}
// 接收消息处理
receiveMessage(event) {
console.log('receiveMessage:', event.data);
this.receiveMessageCallback && this.receiveMessageCallback(event.data);
}
// 关闭WebSocket连接
closeWebSocket() {
this.socket.close();
clearTimeout(this.sendTimeObj);
clearTimeout(this.reconnectTimeObj);
this.reconnectAttempts = 0;
}
}
使用Demo
在页面中可以这样使用该封装类:
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebSocket Demo</title>
<script src="./webSocketManager.js"></script>
<script>
const receiveMessage = (res) => {
console.log('接收消息回调:', res);
};
const socketManager = new WebSocketManager('ws://localhost:3000', 'userid292992', receiveMessage);
socketManager.start();
</script>
</head>
总结
与传统的AJAX轮询相比,WebSocket提供了更加高效的消息推送方式。通过封装一个WebSocket管理器,可以有效处理连接、消息传递和自动重连等操作,使开发过程更加简洁和灵活。