Тайм-аут соединения WebSocket

Я пытаюсь внедрить защищенную оболочку websocket. И проблема, которую я имею, имеет дело с ошибками тайм-аута. Логика должна быть: если сокет не открывается во время $timeoutInMiliseconds - он должен быть закрыт и снова открыт $N раз.

Я пишу что-то вроде этого.

var maxReconects = 0;
var ws = new WebSocket(url);
var onCloseHandler = function() {
    if ( maxReconects < N ) {
        maxReconects++;
        // construct new Websocket 
        ....
    }
};
ws.onclose = onCloseHandler;
var timeout = setTimeout(function() {
                console.log("Socket connection timeout",ws.readyState);
                timedOut = true;
                ws.close();  <--- ws.readyState is 0 here 
                timedOut = false;
},timeoutInMiliseconds); 

Но проблема в правильном обращении с тайм-аутами - если я пытаюсь закрыть не подключенный сокет, я получаю предупреждение в chrome:

"Соединение WebSocket с" ws://127.0.0.1: 9010/timeout "не выполнено: WebSocket закрыт до установления соединения."

И у меня нет идеи, как этого избежать - интерфейс ws не имеет функции прерывания.

Другой aproach, который я пробовал, заключается не в том, чтобы закрыть сокет по таймауту, если он не подключен, а просто пометьте его как не использованный больше и закроет его, если он получит readyState более одного, - но он может создавать возможные утечки и сложный для такого простая задача.

Ответ 1

Ваша переменная timeout назначается функции setTimeout(..., которая вызывается лексически. К моменту, когда ваш код достигнет var onCloseHander = ..., ваша функция timeout уже была вызвана.

Решением этого является создание функции makeTimeout:

var makeTimeout = function (timeoutInMiliseconds) {
    return window.setTimeout(function() {
        // do stuff
    }, timeoutInMiliseconds)
};

var timeoutId = makeTimeout(100) будет вызывать функцию setTimeout и установить timeoutId как значение идентификатора тайм-аута. Если вам нужно отменить этот таймаут, это можно сделать, вызвав window.clearTimeout(timeoutId).