Ole*_*leg 12 javascript websocket
我正在尝试实现failafe 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);
Run Code Online (Sandbox Code Playgroud)
但问题是正确处理超时websockets - 如果我试图关闭未连接的套接字我在chrome中收到警告:
"与'ws://127.0.0.1:9010/timeout'的WebSocket连接失败:在建立连接之前WebSocket已关闭."
我不知道如何避免它 - ws接口没有中止功能.
我尝试过的另一个方法是在超时时关闭套接字,如果它没有连接,只是将其标记为不使用更多,如果接收到readyState不止一个就关闭它 - 但是它可能产生可能的泄漏,并且对于这样简单的任务来说很复杂.
我编写了以下代码,用于打开带有 timeout 和 retries 的 websocket 故障安全,有关更多详细信息,请参阅代码中的注释。
用法- 打开具有 5000 毫秒超时和 10 次重试(最大)的 websocket:
initWebsocket('ws:\\localhost:8090', null, 5000, 10).then(function(socket){
console.log('socket initialized!');
//do something with socket...
//if you want to use the socket later again and assure that it is still open:
initWebsocket('ws:\\localhost:8090', socket, 5000, 10).then(function(socket){
//if socket is still open, you are using the same "socket" object here
//if socket was closed, you are using a new opened "socket" object
}
}, function(){
console.log('init of socket failed!');
});
Run Code Online (Sandbox Code Playgroud)
initWebsocket()在库或类似的地方定义的方法:
/**
* inits a websocket by a given url, returned promise resolves with initialized websocket, rejects after failure/timeout.
*
* @param url the websocket url to init
* @param existingWebsocket if passed and this passed websocket is already open, this existingWebsocket is resolved, no additional websocket is opened
* @param timeoutMs the timeout in milliseconds for opening the websocket
* @param numberOfRetries the number of times initializing the socket should be retried, if not specified or 0, no retries are made
* and a failure/timeout causes rejection of the returned promise
* @return {Promise}
*/
function initWebsocket(url, existingWebsocket, timeoutMs, numberOfRetries) {
timeoutMs = timeoutMs ? timeoutMs : 1500;
numberOfRetries = numberOfRetries ? numberOfRetries : 0;
var hasReturned = false;
var promise = new Promise((resolve, reject) => {
setTimeout(function () {
if(!hasReturned) {
console.info('opening websocket timed out: ' + url);
rejectInternal();
}
}, timeoutMs);
if (!existingWebsocket || existingWebsocket.readyState != existingWebsocket.OPEN) {
if (existingWebsocket) {
existingWebsocket.close();
}
var websocket = new WebSocket(url);
websocket.onopen = function () {
if(hasReturned) {
websocket.close();
} else {
console.info('websocket to opened! url: ' + url);
resolve(websocket);
}
};
websocket.onclose = function () {
console.info('websocket closed! url: ' + url);
rejectInternal();
};
websocket.onerror = function () {
console.info('websocket error! url: ' + url);
rejectInternal();
};
} else {
resolve(existingWebsocket);
}
function rejectInternal() {
if(numberOfRetries <= 0) {
reject();
} else if(!hasReturned) {
hasReturned = true;
console.info('retrying connection to websocket! url: ' + url + ', remaining retries: ' + (numberOfRetries-1));
initWebsocket(url, null, timeoutMs, numberOfRetries-1).then(resolve, reject);
}
}
});
promise.then(function () {hasReturned = true;}, function () {hasReturned = true;});
return promise;
};
Run Code Online (Sandbox Code Playgroud)
更好的解决方案是将功能封装在自己的类中FailsafeWebsocket或其他任何东西中。然而,这个解决方案在我的项目中已经足够了 - 也许它也可以帮助其他人。
小智 2
您的timeout变量被分配给setTimeout(...正在词法调用的函数。当您的代码到达时,var onCloseHander = ...您的timeout函数已经被调用。
解决这个问题的方法是创建一个makeTimeout函数:
var makeTimeout = function (timeoutInMiliseconds) {
return window.setTimeout(function() {
// do stuff
}, timeoutInMiliseconds)
};
Run Code Online (Sandbox Code Playgroud)
var timeoutId = makeTimeout(100)将调用该setTimeout函数并将其设置timeoutId为超时 ID 的值。如果您需要取消此超时,可以通过调用 来完成window.clearTimeout(timeoutId)。
| 归档时间: |
|
| 查看次数: |
25704 次 |
| 最近记录: |