How to wait for a WebSocket's readyState to change

…衆ロ難τιáo~ 提交于 2019-11-26 12:39:45

问题


I\'m trying to implement a WebSocket with a fallback to polling. If the WebSocket connection succeeds, readyState becomes 1, but if it fails, readyState is 3, and I should begin polling.

I tried something like this:

var socket = new WebSocket(url);
socket.onmessage = onmsg;
while (socket.readyState == 0)
{
}
if (socket.readyState != 1)
{
    // fall back to polling
    setInterval(poll, interval);
}

I was expecting socket.readyState to update asynchronously, and allow me to read it immediately. However, when I run this, my browser freezes (I left it open for about half a minute before giving up).

I thought perhaps there was an onreadyStateChanged event, but I didn\'t see one in the MDN reference.

How should I be implementing this? Apparently an empty loop won\'t work, and there is no event for this.


回答1:


This is simple and it work perfectly... you can add condition about maximal time, or number of try to make it more robust...

function sendMessage(msg){
    // Wait until the state of the socket is not ready and send the message when it is...
    waitForSocketConnection(ws, function(){
        console.log("message sent!!!");
        ws.send(msg);
    });
}

// Make the function wait until the connection is made...
function waitForSocketConnection(socket, callback){
    setTimeout(
        function () {
            if (socket.readyState === 1) {
                console.log("Connection is made")
                if (callback != null){
                    callback();
                }
            } else {
                console.log("wait for connection...")
                waitForSocketConnection(socket, callback);
            }

        }, 5); // wait 5 milisecond for the connection...
}



回答2:


Here is a more elaborate explanation. First off, check the specific browser API, as not all browsers will be on the latest RFC. You can consult the

You don't want to run a loop to constantly check the readystate, it's extra overhead you don't need. A better approach is to understand all of the events relevant to a readystate change, and then wire them up appropriately. They are as follows:

onclose An event listener to be called when the WebSocket connection's readyState changes to CLOSED. The listener receives a CloseEvent named "close".

onerror An event listener to be called when an error occurs. This is a simple event named "error".

onmessage An event listener to be called when a message is received from the server. The listener receives a MessageEvent named "message".

onopen An event listener to be called when the WebSocket connection's readyState changes to OPEN; this indicates that the connection is ready to send and receive data. The event is a simple one with the name "open".

JS is entirely event driven, so you need to just wire up all of these events and check for the readystate, this way you can switch from WS to polling accordingly.

I recommend you look at the Mozilla reference, it's easier to read than the RFC document and it will give you a good overview of the API and how it works: see https://developer.mozilla.org/en-US/docs/WebSockets/WebSockets_reference/WebSocket

Don't forget to do a callback for a retry if you have a failure and poll until the callback for a successful reconnect is fired.




回答3:


Look on http://dev.w3.org/html5/websockets/

Search for "Event handler" and find the Table.

onopen -> open
onmessage -> message
onerror ->error
onclose ->close

function update(e){ /*Do Something*/};
var ws = new WebSocket("ws://localhost:9999/");

ws.onmessage = update;



回答4:


I am not using pooling at all. Instead, I use queuing. First I create new send function and a queue:

var msgs = []
function send (msg) {
  if (ws.readyState !== 1) {
    msgs.push(msg)
  } else {
    ws.send(msg)
  }
}

Then I need to read and send when the connection is first established:

function my_element_click () {
  if (ws == null){
    ws = new WebSocket(websocket_url)
    ws.onopen = function () {
      while (msgs.length > 0) {
        ws.send(msgs.pop())
      }
    }
    ws.onerror = function(error) {
      // do sth on error
    }
  } 
  msg = {type: 'mymessage', data: my_element.value}
  send(JSON.stringify(msg))
}

WebSocket connection in this example is created only on the first click. Usually, on second messages start to be sent directly.




回答5:


Your while loop is probably locking up your thread. Try using:

setTimeout(function(){
    if(socket.readyState === 0) {
        //do nothing
    } else if (socket.readyState !=1) {
        //fallback
        setInterval(poll, interval);
    }
}, 50);



回答6:


In my use case, I wanted to show an error on screen if the connection fails.

let $connectionError = document.getElementById("connection-error");

setTimeout( () => {
  if (ws.readyState !== 1) {
    $connectionError.classList.add( "show" );
  }
}, 100 );  // ms

Note that in Safari (9.1.2) no error event gets fired - otherwise I would have placed this in the error handler.




回答7:


If you use async/await and you just want to wait until the connection is available I would suggest this function :

async connection (socket, timeout = 10000) {
  const isOpened = () => (socket.readyState === WebSocket.OPEN)

  if (socket.readyState !== WebSocket.CONNECTING) {
    return isOpened()
  }
  else {
    const intrasleep = 100
    const ttl = timeout / intrasleep // time to loop
    let loop = 0
    while (socket.readyState === WebSocket.CONNECTING && loop < ttl) {
      await new Promise(resolve => setTimeout(resolve, intrasleep))
      loop++
    }
    return isOpened()
  }
}

Usage (in async function) :

const websocket = new WebSocket('...')
const opened = await connection(websocket)
if (opened) {
  websocket.send('hello')
}
else {
  console.log("the socket is closed OR couldn't have the socket in time, program crashed");
  return
}



回答8:


Just like you defined an onmessage handler, you can also define an onerror handler. This one will be called when the connection fails.

var socket = new WebSocket(url);
socket.onmessage = onmsg;
socket.onerror = function(error) {
    // connection failed - try polling
}


来源:https://stackoverflow.com/questions/13546424/how-to-wait-for-a-websockets-readystate-to-change

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!