现象
websocket 先连接成功,然后断网。
由于维护了一套心跳机制,前端发起心跳,如果一段时间内没有收到服务端返回的心跳。则表示连接断开。
用心跳的方式处理断网的兜底情况。
然而,此时网络是断开的,在代码中直接调用websocket.close() 方法,会发现,websocket.readyState 会一直在 WebSocket.CLOSING 状态,等很久也不会触发onclose 回调。
只有网络通的时候才会触发 websocket onclose。
这样会触发不了我的重连逻辑。因为重连逻辑做在onclose 回调里面。
解决
通过定时器检查websocket 的状态,如果在几秒钟之后,还是 CLOSING 状态,则直接调用onclose 的回调。
onclose 的回调有一个参数,可以通过 new CloseEvent 来模拟,代码如下。
const ws = new WebSocket('ws://xxxx');ws.onclose = onclose;function onclose(e){}// 可以在检测到closing 状态超时了后,主动调用onclose 回调,自行模拟eventonclose(new CloseEvent('close', {wasClean: false,code: 3000,reason: 'websocket closing timeout',
}))
还要注意的是,在重新new Websocket 之前,要清除当前的websocket实例,其中的各种回调要置为null (onopen, onclose, onerror, onmessage)
因为等到重连的时候,这个CLOSING 状态的ws实例会触发onclose,导致onclose回调中的内容被重复执行。
参考
- WebSocket.close() - Web API | MDN
- CloseEvent - Web API | MDN