ti-enxame.com

websockets javascript - controle a conexão inicial/quando o onOpen se limita

Duas questões relacionadas que podem estar mais enraizadas em minha falta de conhecimento de como/se os navegadores pré-analisam o javascript:

var ws = new WebSocket("ws://ws.my.url.com");
ws.onOpen = function() { ... };

Parece não haver nenhuma maneira de controlar diretamente a inicialização de um WebSocket, além de envolvê-lo em um retorno de chamada, então eu suponho que a conexão é criada assim que o código javascript é carregado e chegar ao construtor?

Quando a propriedade onOpen é anexada a ws? Existe alguma possibilidade de uma condição de corrida (se por algum motivo você tivesse algum código entre a definição do socket e a definição de onOpen?) Para que onOpen seja indecidamente ligado antes e depois da conexão ser estabelecida (eu sei que você poderia opcionalmente verifique ws.readyState). Complementar a isso, o bloqueio de handshake do WebSocket?

Eu percebo que é tudo um rascunho no momento, possivelmente dependente de implementação e eu posso ter perdido algo que é óbvio, mas não consegui ver nada de pertinente em minhas buscas na internet/examinar as especificações do w3c, então qualquer ajuda na minha compreensão O funcionamento interno do websockets/javascript é muito apreciado!

26
dbeacham

JavaScript é single threaded, o que significa que a conexão de rede não pode ser estabelecida até que o escopo atual da execução seja concluído e a execução da rede tenha a chance de ser executada. O escopo de execução pode ser a função atual (a função connect no exemplo abaixo). Então, você pode perder o evento onopen se ligar muito tarde ao usar um setTimeout, por exemplo neste exemplo, você pode perder o evento:

Visualizar: http://jsbin.com/ulihup/edit#javascript,html,live

Código:

var ws = null;

function connect() {
  ws = new WebSocket('ws://ws.pusherapp.com:80/app/a42751cdeb5eb77a6889?client=js&version=1.10');
  setTimeout(bindEvents, 1000);
  setReadyState();
}

function bindEvents() {
  ws.onopen = function() {
    log('onopen called');
    setReadyState();
  };
}

function setReadyState() {
  log('ws.readyState: ' + ws.readyState);
}

function log(msg) {
  if(document.body) {
    var text = document.createTextNode(msg);
    document.body.appendChild(text);
  }
}

connect();

Se você executar o exemplo, você pode ver que a linha de log 'onopen called' nunca é produzida. Isso é porque perdemos o evento.

No entanto, se você mantiver new WebSocket(...) e a ligação para o evento onopen no mesmo escopo de execução, não há chance de perder o evento.

Para mais informações sobre scope of execution e como elas são enfileiradas, programadas e processadas, dê uma olhada na postagem de John Resig em Timers em JavaScript .

29
leggetter

Preste atenção ao fato de que a E/S pode ocorrer dentro do escopo de execução. Por exemplo, no código a seguir

var ws = new WebSocket("ws://localhost:8080/WebSockets/example");
alert("Hi");
ws.onopen = function(){
    writeToScreen("Web Socket is connected!!" + "<br>");
};
function writeToScreen(message) {
    var div = document.getElementById('test');
    div.insertAdjacentHTML( 'beforeend', message );
}

, a mensagem "Web Socket is connected" será exibida ou não, dependendo de quanto tempo você demorou para fechar o alerta "Hi"

2
Alon Halimi

@ leggetter está certo, seguindo o código executado seqüencialmente:

(function(){
    ws = new WebSocket("ws://echo.websocket.org");
    ws.addEventListener('open', function(e){
        console.log('open', e);
        ws.send('test');
    });
    ws.addEventListener('message', function(e){console.log('msg', e)});

})();

Mas, em W3C spec há uma linha curiosa: 

Retorne um novo objeto WebSocket e continue essas etapas em segundo plano (sem bloquear scripts).

Foi confuso para mim, quando eu estava aprendendo a API do navegador para isso. Eu assumo que os agentes do usuário o ignoram, ou eu estou interpretando mal.

2
senz

Nenhuma E/S real acontecerá até que seu script termine a execução, portanto, não deve haver uma condição de corrida.

1
Jacob