2012-10-06 3 views
5

Il W3C spec suggeriscono seguente implementazione: Alcuni semplice codice per fare qualcosa con i dati da un documento XML inverosimile attraverso la rete:È possibile eseguire l'attivazione di XHR onreadystatechange più volte con readyState = DONE?

function processData(data) { 
    // taking care of data 
} 

function handler() { 
    if(this.readyState == this.DONE) { 
    if(this.status == 200 && 
     this.responseXML != null && 
     this.responseXML.getElementById('test').textContent) { 
     // success! 
     processData(this.responseXML.getElementById('test').textContent); 
     return; 
    } 
    // something went wrong 
    processData(null); 
    } 
} 

var client = new XMLHttpRequest(); 
client.onreadystatechange = handler; 
client.open("GET", "unicorn.xml"); 
client.send(); 

È questa implementazione davvero corretto?

Durante il debug ho trovato casi in cui il gestore di eventi readystatechanged viene chiamato più volte di seguito con lo stesso valore di readyState == 4. Suppongo che questo comportamento sia corretto, poiché le specifiche dicono che ogni cambio di stato deve far scattare il evento, e che readyState deve sempre essere uguale allo stato corrente, quindi se molti eventi si accumulano nella coda degli eventi, è abbastanza ovvio che uno riceverà più chiamate con readyState == 4.

http://jsfiddle.net/44b3P/ - questo è il nell'esempio sopra aumentato con la chiamata debugger per sospendere l'esecuzione subito dopo l'invio della richiesta e con alert() nei processData. Dopo aver annullato l'esecuzione, riceverai 3 avvisi.

Questo esempio di w3c sembra essere una copia & incollata in più punti del Web, in particolare OpenSocial sembra gestire gli eventi xhr in questo modo. È corretto?

risposta

11

Ho visto lo stesso comportamento (DONE 200 è stato colpito più volte, ovvero 2 ... n volte) durante il debug in Strumenti per sviluppatori di Chrome.

per farlo funzionare sempre in modalità debug così, ho trovato due opzioni:

  1. Utilizzare onload per verificare il successo di un XMLHTMLRequest W3C Spec

    client.onload = gestore;

    Questa versione non funzionerà in IE8. Deve essere un browser che implementa l'interfaccia XMLHttpRequestEventTarget

  2. Rimuovere il gestore onreadystatechange non appena si dispone di uno stato DONE 200.

    client.onreadystatechange = function() { 
        // check if request is complete 
        if (this.readyState == this.DONE) { 
         if (this.onreadystatechange) { 
          client.onreadystatechange = null; 
          handler(); 
         } 
        } 
    }; 
    

ho anche aperto un problema in Chromium per questo problema, fornendo il tuo Fiddle (Grazie!)

+1

Proprio come un addendum - utilizzando il codice fornito originariamente, 'this.onreadystatechange = null;' è sufficiente, non è necessario il riferimento originale all'XHR ('client'). – Monchoman45

+0

Non ha funzionato quando ho provato a usare 'delete xhr.onreadystatechange', cambiandolo in' xhr.onreadystatechange = null' ha funzionato bene. –

+0

Ho modificato il codice per usare '= null' invece di' delete' –

0

Non ho mai avuto il mio onreadystatechange gestore eseguito più volte con un readyState di 4.

Penso assumendo una singola esecuzione sul fatto è corretta.

+1

bene, ho. È abbastanza semplice da riprodurre: http://jsfiddle.net/44b3P/ – qbolec

+0

Viene visualizzato un solo avviso ogni volta che ricarico la pagina, mi dispiace. (ultimo Chrome) –

+0

Il problema è SOLO in modalità di debug (l'ho provato solo su Mac). È necessario aprire gli Strumenti per sviluppatori e quindi ricaricare la pagina. Non è anche "deterministico" (per l'utente), poiché a volte (raramente) non accade. Inoltre non sono riuscito a capire la logica di quante volte è chiamato. –