如何等待WebSocket的readyState更改

Ken*_*rey 32 javascript polling websocket

我正在尝试实现一个带回退轮询的WebSocket.如果WebSocket连接成功,则readyState变为1,但如果失败,readyState则为3,我应该开始轮询.

我试过这样的事情:

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

我期待socket.readyState异步更新,并允许我立即阅读.然而,当我运行这个时,我的浏览器会冻结(我放弃它大约半分钟才放弃).

我想也许有一个onreadyStateChanged事件,但我没有在MDN参考中看到一个.

我应该如何实现这个?显然空循环不起作用,并且没有事件发生.

小智 32

这很简单,它完美地工作......你可以添加关于最大时间的条件,或尝试使其更健壮的数量......

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...
}
Run Code Online (Sandbox Code Playgroud)

  • 根据[Axel的回答](http://stackoverflow.com/a/13590558/752843),适当的解决方案是使用事件处理程序. (2认同)

Axe*_*xel 24

这是一个更详细的解释.首先,检查特定的浏览器API,因为并非所有浏览器都在最新的RFC上.你可以咨询一下

您不希望运行循环来不断检查readystate,这是您不需要的额外开销.更好的方法是了解与即时状态更改相关的所有事件,然后适当地连接它们.它们如下:

onclose当WebSocket连接的readyState更改为CLOSED时要调用的事件侦听器.侦听器接收名为"close"的CloseEvent.

onerror发生错误时要调用的事件侦听器.这是一个名为"error"的简单事件.

onmessage从服务器收到消息时要调用的事件侦听器.侦听器接收名为"message"的MessageEvent.

onopen当WebSocket连接的readyState更改为OPEN时要调用的事件侦听器; 这表示连接已准备好发送和接收数据.该活动很简单,名称为"open".

JS完全由事件驱动,因此您只需连接所有这些事件并检查readystate,这样您就可以相应地从WS切换到轮询.

我建议您查看Mozilla参考,它比RFC文档更容易阅读,它将为您提供API的良好概述及其工作原理:请参阅https://developer.mozilla.org/en-US/docs/的WebSockets/WebSockets_reference /的WebSocket

如果您遇到故障并进行轮询,请不要忘记进行重试回调,直到成功重新连接的回调被触发为止.

  • “你可以咨询”...?(我知道它很旧) (2认同)

小智 11

我根本没有使用池化。相反,我使用排队。首先我创建新的发送函数和一个队列:

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

然后我需要在第一次建立连接时读取和发送:

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))
}
Run Code Online (Sandbox Code Playgroud)

本示例中的 WebSocket 连接仅在第一次单击时创建。通常,在第二个消息开始直接发送。


vde*_*nne 8

如果您使用async/await并且只想等到连接可用,我建议使用此功能:

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()
  }
}
Run Code Online (Sandbox Code Playgroud)

用法(在async函数中):

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
}
Run Code Online (Sandbox Code Playgroud)


Ste*_*ker 6

查看http://dev.w3.org/html5/websockets/

搜索"事件处理程序"并找到表.

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

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

ws.onmessage = update;
Run Code Online (Sandbox Code Playgroud)


agr*_*son 0

您的 while 循环可能锁定了您的线程。尝试使用:

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