封装WebSocket消息推送,干翻Ajax轮询方式
内容: 大厂技术 高级前端 Node进阶
点击上方 程序员成长指北,关注公众号
回复1,加入高级Node交流群
使用AJAX和WebSocket都可以实现消息推送,但它们在实现方式和适用场景上有所不同。下面是这两种技术的简要对比:
AJAX 实现消息推送
AJAX(Asynchronous JavaScript and XML)允许在不重新加载整个页面的情况下,与服务器进行数据交换。传统的AJAX并不直接支持实时消息推送,因为它基于请求-响应模式。为了模拟消息推送,通常使用轮询(polling)或长轮询(long-polling)技术。
轮询(Polling)
轮询是定期向服务器发送请求,以检查是否有新消息。这种方法简单但效率较低,因为即使没有新消息,也会频繁地发送请求。
function pollForMessages() {
$.ajax({
url: '/messages', // 假设这是获取消息的API端点
method: 'GET',
success: function(data) {
// 处理接收到的消息
console.log(data);
// 每5秒轮询一次
setTimeout(pollForMessages, 5000);
},
error: function() {
// 处理请求失败的情况
setTimeout(pollForMessages, 10000); // 等待更长时间后重试
}
});
}
// 开始轮询
pollForMessages();
长轮询(Long-Polling)
长轮询是轮询的一种改进方式。客户端发起一个请求到服务器,服务器保持这个连接直到有新消息到达或超时。这种方式减少了无效的请求,但仍然存在一定的延迟和资源浪费。
WebSocket 实现消息推送
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通常依赖于特定的服务器软件或框架,如Node.js的ws
库、Java的Spring WebSocket等。这些库或框架提供了处理WebSocket连接的API,可以在这些连接上发送和接收消息。
封装WebSocket的实现
想象一下,你是一位超级快递员,负责将WebSocket消息准确无误地送到指定的地址。这些包裹里装的是WebSocket消息,而你的任务是根据每个包裹上的userid
和url
信息,找到正确的收件人并将包裹送达。
WebSocketMessenger(快递服务公司)
- 职责:建立和维护WebSocket连接。
- 特点:采用单例模式,确保同一时间只有一个实例在运行,存储收件人(recipient)和地址(address)信息,提供发送消息(send_message)的方法。
快递员(WebSocket连接实例)
- 职责:由WebSocketMessenger创建和管理,负责实际的消息传递工作,知道如何与指定的收件人通信(通过地址)。
代码实现
class WebSocketManager {
constructor(url = null, userId = null, receiveMessageCallback = null) {
this.socket = null; // WebSocket 对象
this.sendTimeObj = null; // 发送信息给服务端的重复调用的时间定时器
this.reconnectTimeObj = null; // 尝试链接的宏观定时器
this.reconnectTimeDistance = 5000; // 重连间隔,单位:毫秒
this.maxReconnectAttempts = 10; // 最大重连尝试次数
this.reconnectAttempts = 0; // 当前重连尝试次数
this.id = userId; // 用户ID
this.url = url; // WebSocket 连接地址
this.receiveMessageCallback = receiveMessageCallback; // 接收消息回调函数
}
/**
* 开启WebSocket
*/
async start() {
if (this.url && this.id) {
// 连接WebSocket
this.connectWebSocket();
} else {
console.error('WebSocket erros: 请传入连接地址和用户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++;
console.log('重试链接次数:' + this.reconnectAttempts);
this.reconnectTimeObj = setTimeout(() => {
this.connectWebSocket();
}, this.reconnectTimeDistance);
} else {
this.reconnectAttempts = 0;
console.error('WebSocketManager erros: Max reconnect attempts reached. Unable to reconnect.');
}
};
this.socket.onerror = (event) => {
console.error('WebSocketManager error:', event);
};
}
/**
* 发送给node的第一条信息
*/
startSendServe() {
this.sendMessage('hi I come from client');
}
/**
* 发送消息
* @param {String} message 消息内容
*/
sendMessage(message) {
if (this.socket.readyState === WebSocket.OPEN) {
this.socket.send(message);
} else {
console.error('WebSocketManager error: WebSocket connection is not open. Unable to send message.');
}
}
/**
* 接收到消息
*/
receiveMessage(event) {
console.log('receiveMessage:', event.data);
this.receiveMessageCallback && this.receiveMessageCallback(event.data);
}
/**
* 关闭连接
*/
closeWebSocket() {
this.socket.close();
clearTimeout(this.sendTimeObj);
clearTimeout(this.reconnectTimeObj);
this.reconnectAttempts = 0;
}
}
使用示例
<!DOCTYPE html>
<html lang="en">
<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>
console.log(WebSocketManager);
/**
* 接收消息回调
*/
const receiveMessage = (res) => {
console.log('接收消息回调:', res);
};
const socketManager = new WebSocketManager('ws://localhost:3000', 'userid292992', receiveMessage);
socketManager.start();
</script>
</head>
<body>
</body>
</html>
导入模块后即可使用。
总结
该WebSocket管理器能够处理连接建立、消息接收和重连等常见场景。具体的业务逻辑和错误处理可根据实际情况进行进一步优化。