2012-11-24 8 views
23

Sto cercando di implementare un WebSocket con un fallback polling. Se la connessione WebSocket ha esito positivo, readyState diventa 1, ma se non riesce, readyState è 3 e dovrei iniziare il polling.Come attendere readyState di un WebSocket per cambiare

Ho provato qualcosa di simile:

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

mi aspettavo socket.readyState per aggiornare in modo asincrono, e mi permette di leggere immediatamente. Tuttavia, quando eseguo questo, il mio browser si blocca (l'ho lasciato aperto per circa mezzo minuto prima di mollare).

Ho pensato che forse c'era un evento onreadyStateChanged, ma non ne ho visto uno nel riferimento MDN.

Come dovrei attuando questo? Apparentemente un ciclo vuoto non funzionerà, e non c'è nessun evento per questo.

+0

Erm ... Mi può mancare qualcosa, ma perché non usi 'socket.onopen'? – raina77ow

+0

@ raina77ow Non penso che 'socket.onopen' si attivi se il socket non viene mai aperto. –

+0

Sì, ma cosa dovrebbe fare il tuo codice in questo caso? 'Aspettando che la presa sia aperta' non è ovviamente una risposta, suppongo.) – raina77ow

risposta

0

vostro ciclo while è probabilmente chiudendo il tuo thread. Prova con:

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

E il primo 'if' è necessario per cosa esattamente? – raina77ow

+0

Se ho capito bene, 'readyState' non viene aggiornato immediatamente. Ecco perché ho usato un ciclo. –

+0

Onestamente non lo so, presumo lo stesso del ciclo while nella domanda OP. Ovviamente può essere rimosso a meno che OP non abbia bisogno di qualcosa mentre 'socket.readyState === 0', sto cercando di non lasciare nulla in sospeso. – agryson

0

Proprio come è stato definito un onmessage gestore, è anche possibile definire un onerror gestore. Questo verrà chiamato quando la connessione fallisce.

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

Ho provato e non si accende. –

+0

Lo sto usando nella mia applicazione, e si chiama abbastanza affidabile ogni volta che c'è qualcosa di sbagliato nella connessione al server. Hai ancora quel giro occupato nel tuo codice? Potrebbe mantenere il motore JS troppo occupato per eseguire la gestione degli errori. – Philipp

+0

Ho commentato il ciclo while e ho fatto un rapido test con 'onerror'. Non è stato eseguito. Sono abbastanza sicuro che il server non si sta chiudendo immediatamente, dal momento che 'onopen' non viene eseguito neanche.Penso che piuttosto che un errore che si verifica, il server sta rifiutando la connessione. –

20

Ecco una spiegazione più elaborata. Per prima cosa, controlla l'API del browser specifica, poiché non tutti i browser si troveranno nell'ultima RFC. È possibile consultare il

Non si desidera eseguire un ciclo per controllare costantemente lo stato readystate, è un overhead aggiuntivo di cui non si ha bisogno. Un approccio migliore consiste nel comprendere tutti gli eventi rilevanti per un cambiamento di stato pronto e quindi collegarli in modo appropriato. Sono i seguenti:

onclose Un listener di eventi da chiamare quando il readyState della connessione WebSocket passa a CLOSED. Il listener riceve un CloseEvent denominato "close".

onerror Un listener di eventi di essere chiamato in caso di errore. Questo è un semplice evento chiamato "errore".

onmessage Un listener di eventi da chiamare quando viene ricevuto un messaggio dal server. Il listener riceve un MessageEvent chiamato "messaggio".

onopen Un listener di eventi da chiamare quando il readyState della connessione WebSocket passa a OPEN; questo indica che la connessione è pronta per inviare e ricevere dati. L'evento è semplice con il nome "aperto".

JS è interamente basato su eventi, quindi è sufficiente collegare tutti questi eventi e verificare la disponibilità, in questo modo è possibile passare da WS a polling di conseguenza.

vi consiglio di guardare al riferimento di Mozilla, è più facile da leggere che il documento RFC e che vi darà una buona panoramica delle API e come funziona: vedi https://developer.mozilla.org/en-US/docs/WebSockets/WebSockets_reference/WebSocket

Non dimenticare di fare un callback per un tentativo se si dispone di un errore e il polling fino a quando non viene attivata la richiamata per una riconnessione riuscita.

+0

"puoi consultare il" ...? (So ​​che è vecchio) – akauppi

+0

Leggere questo, ha senso, eccetto che tutti gli eventi "on" non espongono la chiusura e la connessione. Solo gli eventi onopen, onclose e error. Non voglio inviare un messaggio in basso a ws in chiusura. –

4

sguardo sul http://dev.w3.org/html5/websockets/

La ricerca di "gestore di eventi" e trovare la tabella.

SuApertura -> aperto
onMessage -> messaggio
onerror -> errore
OnClose -> close

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

ws.onmessage = update; 
+0

Ho eseguito il upvoted perché il collegamento w3 è stato utile. – javadba

21

Questo è semplice e funziona perfettamente ... è possibile aggiungere condizioni circa il tempo massimo, o il numero di provare a renderlo più robusto ...

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(); 
       } 
       return; 

      } else { 
       console.log("wait for connection...") 
       waitForSocketConnection(socket, callback); 
      } 

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

Potrebbe semplicemente essermi mancato qualcosa, ma quando eseguo il codice ricevo un errore che mi dice che "la richiamata non è una funzione". Perché la funzione callback è attiva nel 'if (callback! = Null) { callback(); } ' –

+1

La soluzione appropriata è utilizzare eventhandlers, per [risposta di Axel] (http://stackoverflow.com/a/13590558/752843). – Richard

+0

Ciò che mi sembra strano è l'idea che i websocket siano una tecnologia push, ma che abbiano readyState come una chiamata sincrona e non push. –

0

Nel mio caso d'uso, volevo mostrare un errore sullo schermo se la connessione fallisce.

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

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

Si noti che in Safari (9.1.2) non error evento viene attivato - altrimenti mi avrebbe messo questo nel gestore di errori.

0

Non sto utilizzando il pooling. Invece, uso la coda. Per prima cosa ho creare nuova funzione di invio e una coda:

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

poi ho bisogno di leggere e inviare quando la connessione viene stabilito in primo luogo:

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)) 
} 

connessione WebSocket in questo esempio viene creato solo sulla prima clic. Di solito, sui secondi messaggi iniziano ad essere inviati direttamente.

Problemi correlati