2010-02-03 12 views
5

Ho una chiamata Ajax che al momento deve essere sincrona. Tuttavia, mentre questa chiamata Ajax è in esecuzione, l'interfaccia del browser si blocca fino a quando la chiamata non ritorna. In caso di timeout, questo può bloccare il browser per un significant period of time.È possibile ottenere una finestra del browser per l'aggiornamento mentre è in un ciclo di Javascript?

C'è un modo per ottenere il browser (qualsiasi browser) per aggiornare l'interfaccia utente, ma non eseguire alcun Javascript? Idealmente sarebbe un comando come window.update(), che consentirebbe l'aggiornamento del thread dell'interfaccia utente.

Se ciò fosse possibile, allora potrei sostituire la chiamata AJAX sincrono con qualcosa di simile:

obj = do_async_ajax_call(); 
while (!obj.hasReturned()) { 
    window.update(); 
} 
// synchronous call can resume 

La ragione per cui non posso usare setTimeout, o riprendere una funzione nella callback, è che il flusso di esecuzione non può essere interrotta: (ci sono troppe variabili di stato che tutti dipendono l'uno dall'altro, e il flusso long_function() avrebbe altrimenti essere ripreso in qualche modo):

function long_function() { 
    // lots of code, reads/writes variable 'a', 'b', ... 
    if (sync_call_is_true()) { 
    // lots of code, reads/writes variable 'a', 'b', ... 
    } else { 
    // lots of code, reads/writes variable 'a', 'b', ... 
    } 
    // lots of code, reads/writes variable 'a', 'b', ... 
    return calculated_value; 
} 
+2

Perché la chiamata deve essere sincrona? –

+1

Puoi pubblicare l'intero codice di chiamata? Questo può probabilmente essere semplificato e utilizzare le funzioni XHR per supportare ciò che è necessario (a meno che jQuery non sia un'opzione, quindi ancora più pulito). Se nessuna delle due è un'opzione, ti chiedo di rinominare la funzione in 'do_sync_jax_call();' –

risposta

3

È necessario sostituire la vostra richiesta sincrona con una richiesta asincrona e utilizzare un callback. Un esempio potrebbe essere semplificato:

obj = do_async_ajax_call(function (data, success) 
{ 
    if (success) 
    { 
     // continue... 
    } 
}); 

function do_async_ajax_call(callback) 
{ 
    var xhr = new XMLHttpRequest(); 
    xhr.open("GET", "http://mysite.com", true); 
    xhr.onreadystatechange = function() 
    { 
     if (xhr.readyState == 4 && xhr.status == 200) 
      callback(xhr.responseXML, true); 
     else if (xhr.readyState == 4) 
      callback(null, false); 
    } 
    xhr.send(); 
} 

In questo modo si sta passando una funzione anonima come parametro alla funzione richiesta ajax. Quando l'ajax è completo, la funzione che è stata passata viene chiamata con il responseXML passato ad essa. Nel frattempo, il browser è stato libero di fare la cosa normale fino al completamento della chiamata. Da qui, il resto del tuo codice continua.

+0

Questo normalmente sarebbe sufficiente, ma non posso dividere il flusso operativo (come aggiornato nella domanda). Sto provando un altro approccio ora ... – jevon

+0

È sempre * possibile dividerlo; questa è la trasformazione di CPS (cercare lo "stile di passaggio continuo", il parametro di continuazione è il callback). Le variabili di stato locali sono semplicemente chiuse nella funzione di callback. I loop diventano chiamate ricorsive. Non è così difficile o oscuro una volta capito. –

+0

Sono d'accordo è sempre possibile, ma in questo caso non era la soluzione migliore (c'erano troppe variabili di stato!) :) Alla fine, ho usato il risultato di precedenti callback (o regolari polling del server) per aggiornare il client a fianco con un valore memorizzato nella cache della chiamata sincrona quando necessario, quindi non è necessario chiamare Ajax. – jevon

0

prendere il resto della chiamata e metterlo nel callback che viene chiamato quando il risultato ritorna. Dubito seriamente che ciò sia completamente impossibile per te. Qualsiasi logica è necessario mettere al bando può essere duplicato nel callback

0

ajax recupero asincrono poi setTimeout e fare il lavoro di trasformazione in blocchi (innescato dalla callback)

0

JavaScript è a thread singolo. Quindi, per definizione, non è possibile aggiornare l'interfaccia utente mentre si è in un ciclo di marea. Tuttavia, a partire da Firefox 3.5 è stato aggiunto il supporto per JavaScripts multi-thread denominati web worker. I lavoratori Web non possono influenzare l'interfaccia utente della pagina, ma non bloccano neanche gli aggiornamenti dell'interfaccia utente. Noi lavoratori siamo supportati anche da Chrome e Safari.
Il problema è che, anche se si sposta la chiamata AJAX in thread in background e si attende il completamento dell'esecuzione, gli utenti saranno in grado di premere i pulsanti e modificare i valori sull'interfaccia utente (e per quanto ho capito, questo è ciò che si è cercando di evitare). L'unica cosa che posso suggerire di impedire agli utenti di causare qualsiasi modifica è una selezione che bloccherà l'intera interfaccia utente e non consentirà alcuna interazione con la pagina fino a quando non verrà restituita la chiamata.

+0

Non mi interessa se gli utenti interagiscono con la pagina (e l'interazione è in coda); ma attualmente, mentre una chiamata Ajax sincrona è in esecuzione in Firefox, l'intero browser si blocca. Questo è quello che voglio impedire. – jevon

Problemi correlati