現象
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