前言
WebSocket是一种基于TCP协议的全双工通信协议,它通过一个初始的握手过程建立连接,然后保持连接开放,双方可以随时向对方发送消息。这与传统的HTTP通信不同,HTTP通信需要客户端发起请求,服务器响应后连接就会关闭,而WebSocket则支持双向通信,允许服务器主动向客户端推送数据。
实时聊天对话中的WebSocket应用
在实时聊天对话中,实时性对于提供出色的用户体验至关重要。WebSocket的引入使得开发者能够轻松实现实时消息传递,而不必依赖传统的轮询方式。
WebSocket的优势
- 低延迟通信: WebSocket通过建立持久连接,降低了通信的延迟。消息可以即时传递,使得用户能够实时看到对方的消息。
- 双向通信: 与HTTP不同,WebSocket支持双向通信,服务器可以主动推送消息给客户端,而不需要等待客户端的请求。
- 减轻服务器压力: 相比传统的轮询方式,WebSocket减轻了服务器的负担。在WebSocket中,连接保持开放,减少了频繁的连接和断开操作。
/**
* 发起websocket请求函数
* @param {object} wsObj - ws对象
* @param {string} type - 操作websocket:销毁close、创建create
* @param {number} timeout - 心跳间隔时长,默认5000ms
* @param sendHeartBeat - 以心跳,内容体区分string、object
* @param {function} msgCallback - 接收到ws数据,对数据进行处理的回调函数
* @param {function} reCallback - ws每次重连时,暴露对外的回调函数
*/
export function websocketCommand(wsObj,type,timeout=5000, sendHeartBeat, msgCallback, reCallback, openCallback) {
let lockReconnect = false; // 是否真正建立连接
let timeoutnum = null; // 断开 重连倒计时
//心跳检测
let heartCheck = {
timeout: 55000, //1分钟发一次心跳,时间设置小一点较好(50-60秒之间)
timeoutObj: null,
serverTimeoutObj: null,
reset: function () {
clearTimeout(this.timeoutObj);
clearTimeout(this.serverTimeoutObj);
return this;
},
start: function () {
let self = this;
this.timeoutObj = setTimeout(function () {
//这里发送一个心跳,后端收到后,返回一个心跳消息,
//onmessage拿到返回的心跳就说明连接正常
if(wsObj.readyState === 1) {
websocketSend()
}
self.serverTimeoutObj = setTimeout(function () {//如果超过一定时间还没重置,说明后端主动断开了
wsObj.close(); //如果onclose会执行reconnect,我们执行socket.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
}, self.timeout)
}, this.timeout)
}
}
// 若type传入close,则意图销毁websocket
if(type==='close'){
onClose('close');
}
// 若type传入create,则意图新建websocket,需初始化ws并发送心跳
if(type==='create'){
initWebsocket();
websocketSend();
}
function initWebsocket(){
if (typeof (WebSocket) === 'undefined') {
console.log('您的浏览器不支持WebSocket,无法获取数据');
return false;
}
wsObj.onmessage = function (e) { onMessage(e) };
wsObj.onopen = function (e) { onOpen(e) };
wsObj.onerror = function (e) { onError(e) };
wsObj.onclose = function (e) { onClose(e) } ;
}
function websocketSend () {
// 加延迟是为了尽量让ws连接状态变为OPEN
setTimeout(() => {
wsObj.send(sendHeartBeat)
}, 500)
}
function onMessage(evt) {
var received_msg = evt && JSON.parse(evt.data);
msgCallback(received_msg);
// 收到服务器信息, 重置服务器心跳
heartCheck.reset().start(); //心跳检测重置
}
function onError(e) {
reconnect(); //尝试重新连接
console.log('连接错误', e);
}
function onOpen(e) {
console.log('连接开启', e)
// 连接成功向服务器发送信息,并开启心跳
if(openCallback){
openCallback()
}
heartCheck.reset().start(); //心跳检测重置
}
function reconnect(e) {
console.log('执行重连', e)
// 避免重复建立连接
if (lockReconnect) {
return;
}
lockReconnect = true;
// 没连接上会一直重连,设置延迟避免请求过多
timeoutnum && clearTimeout(timeoutnum);
timeoutnum = setTimeout(function() {
// 重连
initWebsocket();
// 若重连后有需额外处理的逻辑,通过reCallback()回调暴露出去
// reCallback?.();
lockReconnect = false;
}, timeout);
}
function onClose(e) {
if(typeof e === 'string') {
console.log('断开链接');
// 如果ws连接正常,则清计时器、断开连接
wsObj?.close?.();
heartCheck.reset()
} else {
reconnect(); //尝试重新连接
console.log('连接关闭', e);
}
}
}
结语:在使用过程当中我们还需要注意网络断开链接的情况,以及组件销毁的情况,我们要及时销毁,避免不必要的资源占用