开发一个通用socket客户端
coderzhouyujavascriptsocket
1. 通用 socket 客户端
/**
* 服务端适配需要按照以下格式发送数据
* {
* event: "hello", // 事件名称
* data: "world", // 传递的数据
* eventId: "hello:123456" // 事件唯一标识(前端发送数据时会返回) 如果有回调函数则需要
* }
*
* on(event,cb) 注册事件 默认事件 connect close error message ping
* emit(event,data,callback) 触发事件
* emit(event,callback) 触发事件
* close() 关闭连接
* reconnect() 重连
* bear() 心跳检测
* cancelBear() 取消心跳检测
* removeEvent(event) 移除事件
* removeAllEvent() 移除所有事件
*
*
* 快速开始
* const socket = new SimpleSocket("ws://localhost:3000");
* socket.on("connect",() => {
* console.log("connect")
* socket.emit("hello","world",(data) => {
* console.log(data)
* })
*
* socket.emit("hello","file",(data) => {
* console.log(data)
* })
* socket.emit("hello","world")
* socket.emit("hello",data=>{
* console.log(data)
* })
*/
class SimpleSocket {
constructor(url, options) {
// 默认配置
this.options = {
reconnection: true, // 是否重连
reconnectionAttempts: 10, // 重连次数
reconnectionDelay: 1000, // 重连延迟
reconnectionDelayMax: 5000, // 最大重连延迟
bear: true, // 心跳检测
bearTime: 5000, // 心跳检测时间
bearEvent: "ping", // 心跳检测事件
bearMsg: "ping", // 心跳检测消息
};
this.options = {
...this.options,
...options,
};
// 保存默认配置
this._options = {
...this.options,
};
this._bearTimer = null;
this._url = url;
// 事件列表
this._eventList = {
connect: [],
close: [],
error: [],
message: [],
};
// 回调函数列表
this._callbackList = {};
this._socket = new WebSocket(this._url);
this._bindEvent();
}
_bindEvent() {
this._unbindEvent();
this._socket.onopen = (event) => {
this._eventList.connect.forEach((cb) => {
cb(event);
});
// 心跳检测
if (this.options.bear) {
this.bear();
}
};
this._socket.onclose = (event) => {
this._eventList.close.forEach((cb) => {
cb(event);
});
};
this._socket.onerror = (event) => {
this._eventList.error.forEach((cb) => {
cb(event);
});
// 重连
this.reconnect();
};
this._socket.onmessage = (ev) => {
// 解析数据
const { event, data, eventId } = JSON.parse(ev.data);
if (eventId) {
// 有回调函数
this._callbackList[eventId](data);
delete this._callbackList[eventId];
} else {
// 同步事件
this._eventList[event].forEach((cb) => {
cb(data);
});
}
};
}
_unbindEvent() {
this._socket.onopen = null;
this._socket.onclose = null;
this._socket.onerror = null;
this._socket.onmessage = null;
}
on(event, cb) {
this._eventList[event].push(cb);
}
emit(event, data, callback) {
// 注册回调函数 生产唯一标识
const id =
event +
":" +
Date.now() +
":" +
Math.random().toString(36).substring(2, 5);
if (data instanceof Function) {
callback = data;
data = null;
}
if (callback instanceof Function) {
this._callbackList[id] = callback;
}
// 发送数据
this._socket.send(
JSON.stringify({
event,
data,
id,
})
);
}
close() {
this._socket.close();
}
reconnect() {
// 注销之前的事件
// 判断是否重连
if (!this.options.reconnection) {
return;
}
// 是否已经连接
if (this._socket.readyState === WebSocket.OPEN) {
// 已经连接 恢复默认值
this.options = this._options;
this._bindEvent();
return;
}
// 重连次数是否超过
if (this.options.reconnectionAttempts <= 0) {
return;
}
// 是否超过最大重连时间
if (this.options.reconnectionDelayMax <= 0) {
return;
}
// 重连
this.options.reconnectionAttempts--;
this.options.reconnectionDelayMax -= this.options.reconnectionDelay;
setTimeout(() => {
this._socket = new WebSocket(this._url);
this.reconnect();
}, this.options.reconnectionDelay);
}
bear() {
// 心跳检测
this._bearTimer = setInterval(() => {
this.emit(this.options.bearEvent, this.options.bearMsg, () => {
console.log("pong");
});
}, this.options.bearTime);
}
cancelBear() {
clearInterval(this._bearTimer);
}
removeEvent(event) {
this._eventList[event] = [];
}
removeAllEvent() {
this._eventList = {
connect: [],
close: [],
error: [],
message: [],
};
}
}