搞实时通信,WebSocket 算是标配。但直接裸用原生 API 会有不少暗坑:连接断了不会自动重连,长时间闲置被代理或防火墙掐掉,消息一多处理逻辑就散得没法维护。这篇文章准备从零搭一个足够健壮的 WebSocket 客户端,涵盖重连、心跳、消息分发,再加几个生产环境常用的变体。
原生 WebSocket 的尴尬
下面这种写法估计很多人都用过:
const socket = new WebSocket('ws://localhost:8080');
socket.onopen = () => socket.send('Hello');
socket.onmessage = (e) => console.log(e.data);
socket.onclose = () => console.log('closed');
socket.onerror = (e) => console.error(e);
问题明显:
- 断开后悄无声息,没有任何重连尝试。
- 没有心跳,中间链路可能会悄悄回收连接。
onmessage里的if/else会随着消息类型增加迅速膨胀。- 错误处理基本等于没写。
所以我们需要自己封装一层。
基础连接类
先把重连、心跳和消息处理器包装起来。核心思路:用一个 WebSocketClient 类管理生命周期,通过 on(type, handler) 注册不同类型的消息回调,内部维护重连次数和心跳定时器。
class WebSocketClient {
constructor(url) {
this.url = url;
this.socket = null;
this.connected = false;
this. = ;
. = ;
. = ;
. = {};
. = ;
}
() {
. = (.);
.. = {
.();
. = ;
. = ;
.();
};
.. = {
.(event.);
};
.. = {
.();
. = ;
.();
.();
};
.. = {
.(, error);
};
}
() {
(. < .) {
.++;
.();
( .(), . * .);
} {
.();
}
}
() {
. = ( {
(.) {
.({ : });
}
}, );
}
() {
(.) {
(.);
. = ;
}
}
() {
(.) {
..(.(data));
} {
.();
}
}
() {
(!.[type]) {
.[type] = [];
}
.[type].(handler);
}
() {
{
message = .(data);
{ type, payload } = message;
(.[type]) {
.[type].( (payload));
}
} (error) {
.(, error);
}
}
() {
.();
(.) {
..();
}
}
}

