2009-05-09 14 views
10

Mi chiedevo se esiste una soluzione per eseguire la sincronizzazione nel codice JavaScript. Ad esempio, ho il seguente caso: sto tentando di memorizzare alcuni valori di risposta dalla chiamata AJAX, il problema è che è possibile eseguire contemporaneamente più chiamate, quindi porta a condizioni di competizione nel codice. Quindi sono molto curioso di trovare una soluzione per questo? Qualcuno ha idea che fare?Opzioni di sincronizzazione JavaScript

risposta

4

Ho trovato la soluzione per il mio problema. Devo dire che non è perfetto come stavo cercando, ma finora funziona e ci penso più come temporaneamente a lavorare.

$.post("url1", function(data) 
{ 
    // do some computation on data and then 
    setSomeValue(data); 
}); 

var setSomeValue = (function() 
{ 
    var cache = {}; 
    return function(data) 
    { 
     if (cache[data] == "updating") 
     { 
      setTimeout(function(){ setSomeValue(data);}, 100); 
      return; 
     } 
     if (!cache[date]) 
     { 
      cache[date] = updating; 
      $.post("url2", function(another_data) 
      { 
        //make heavy computation on another_data 
        cache[data] = value; 
        // update the UI with value 
      }); 
     } 
     else 
     { 
      //update the UI using cached value 
     } 
    } 
})(); 
+0

Grazie per questo. Sono sorpreso di come molti abbiano detto "è single threaded quindi non è un problema" che è totalmente scorretto in un mondo con callback asincroni. Hai descritto bene il problema e questo è un approccio perfettamente efficace per me. –

6

Javascript è intrinsecamente a thread singolo, almeno per il normale ambiente del browser. Non ci saranno mai due esecuzioni simultanee di script che accedono allo stesso documento. (I nuovi thread di lavoro di Javascript potrebbero essere un'eccezione qui, ma non sono pensati per accedere ai documenti affatto, solo per comunicare passando il messaggio).

+1

Javascript può essere a thread singolo ma è possibile avere condizioni di gara, non c'è alcuna garanzia dell'ordine in cui vengono fatte richieste asincrone, quando vengono completate, ecc. Ciò è particolarmente vero con le aggiunte di firefox e le finestre multiple. –

+1

ovviamente hai bisogno di scrivere codice in grado di gestire i problemi che descrivi. Questo non è lo stesso tipo di sincronizzazione di cui hai bisogno in altri linguaggi per evitare che i thread interferiscano tra loro leggendo risultati incompleti dalla memoria o sovrascrivendo le modifiche reciproche tra operazioni più grandi. C'è solo un flusso attivo di esecuzione javascript nell'ambiente del browser. tutti i gestori di eventi sono chiamati in modo serializzato uno dopo l'altro. – fforw

+1

Basta provare a scrivere ad esempio una chiamata AJAX, quindi nel gestore chiamare un'altra richiesta AJAX e nel secondo gestore accedere ad alcune variabili globali. E ora fai diverse iterazioni della prima chiamata. Sei ancora sicuro che ci sia un accesso serializzato a quella variabile? Potrebbe prevedere l'ordine? E un'altra cosa se potessi scrivere codice funzionante per un problema che ho descritto non chiederei mai aiuto qui. –

3

Sì, è possibile rendere sincrono xmlHttpRequests, in non-IE impostare asynch option su falso sul metodo aperto, nei browser IE do the same con il parametro bAsync.

Forse potresti voler concatenare le tue richieste in qualche modo. Crea uno stack di que e invia le richieste mentre fai la coda.

+1

le richieste sincrone sono errate perché impediscono l'esecuzione di tutti gli altri gestori di eventi javascript. – fforw

+0

Ho appena risposto alla sua domanda, non ho tentato di giudicare il suo bisogno. Downvote quello? eh. –

+0

Le persone possono volere la sincronizzazione per molti motivi diversi, ad esempio si desidera che una richiesta venga elaborata prima di gestire qualsiasi altro input da parte dell'utente. Ci sono altri motivi. Etc. –

3

Innanzitutto, è importante sapere che tutte le implementazioni JS correnti sono a thread singolo, pertanto non stiamo discutendo le condizioni di gara e la sincronizzazione nel contesto in cui viene solitamente utilizzata.

Come nota a margine, i browser stanno ora introducendo thread di lavoro che consentiranno la concorrenza in JS, ma per ora questo non è il caso.

Ad ogni modo, si riscontrano ancora problemi con i dati che si prevede di ricevere in risposta alle chiamate asincrone e non si ha alcuna garanzia sull'ordine in cui si riceveranno le cose.

JS offre una soluzione molto bella a questo con i callback. Per ogni evento asincrono che invierai, allega una funzione di callback appropriata, che gestirà l'evento correttamente. Sincronizzazione, nel modo in cui lo intendi, dovrebbe accadere lì.

+0

Ok, io il mio caso sto cercando di costruire la cache per alcune risposte dal server. Esiste una chiamata AJAX, che ha il proprio gestore, ma nel gestore è presente una chiamata per la funzione, che accede alla variabile cache e se la variabile è impostata, utilizzarla per eseguire un'altra pesante chiamata AJAX. Quindi, se sto usando una chiamata asincrona, probabilmente potrei perdere l'aggiornamento della cache ed eseguire due volte chiamate non necessarie, questo comportamento non è voluto, quindi stavo pensando a come sincronizzare l'accesso per la lettura/scrittura di quella variabile. –

8

Posso offrire una possibile soluzione, ma senza vedere il codice ... non sono completamente sicuro di quello che stai facendo, ma non c'è motivo per cui non potresti farlo.

codice di base in jQuery: (non testato e abbreviata ... ma ho fatto cose simili)

var needAllThese = {}; 

$(function(){ 

     $.ajax("POST","/somepage.aspx",function(data) { 
      needAllThese.A = "VALUE"; 
     }); 

     $.ajax("POST","/somepage2.aspx",function(data) { 
      needAllThese.B = "VALUE"; 
     }); 

     $.ajax("POST","/somepage3.aspx",function(data) { 
      needAllThese.C = "VALUE"; 
     }); 

     startWatching(); 
}); 

function startWatching() { 
    if (!haveEverythingNeeded()) { 
     setTimeout(startWatching,100); 
     return; 
    } 
    everythingIsLoaded(); 
} 

function haveEverythingNeeded() { 
    return needAllThese.A && needAllThese.B && needAllThese.C; 
} 

function everythingIsLoaded() { 
    alert("Everything is loaded!"); 
} 

EDIT: (re: il tuo commento)

siete alla ricerca di callback, nello stesso modo in cui lo farebbe jQuery.

var cache = {}; 

    function getSomeValue(key, callback) { 
     if (cache[key]) callback(cache[key]); 

     $.post("url", function(data) { 
      setSomeValue(key,data); 
      callback(cache[key]); 
     }); 
    } 

    function setSomeValue(key,val) { 
     cache[key] = val; 
    } 

    $(function(){  
     // not sure you would need this, given the code above 
     for (var i = 0; i < some_length; ++i) { 
      $.post("url", function(data){ 
       setSomeValue("somekey",data); 
      }); 
     } 

     getSomeValue("somekey",function(val){    
      $("#element").txt(val);    
     };    
    }); 
+0

codice simile a questo: $ (function() { for (var i = 0; i

+0

Ad essere sincero non sono sicuro di capire come l'ultima soluzione mi aiuterà nel mio problema. Ti dispiace spiegare un po '? –

+0

Fa esattamente quello che hai chiesto. Usando i callback ... e se hai scritto il codice di esempio nel tuo commento, stai usando i callback nella tua. $ Post call, è lo stesso concetto ... non dovresti avere problemi a capirlo a meno che tu non abbia scritto il codice hai problemi con –

1

So che è molto tempo dopo, ma ho pensato di dare un miglioramento. Artem Barger ha elaborato la propria soluzione che utilizza setTimeout se il valore memorizzato nella cache è "in fase di aggiornamento" ... Contrassegna semplicemente la funzione su una coda collegata rispetto al valore memorizzato nella cache in modo da avere un oggetto che contiene i dati memorizzati nella cache e la coda delle funzioni chiamare con i dati memorizzati nella cache una volta restituiti i dati.

Quindi, se è "aggiornamento" basta aggiungere la funzione alla coda che è collegata ai dati dell'articolo e quando i dati restituiti ...imposta i dati e poi itera sulla coda delle funzioni (callback) e chiamali con i dati restituiti.

se si desidera ottenere informazioni tecniche, è possibile impostare un timeout QOS specifico mentre si passa attraverso la coda, impostare un cronometro all'inizio dell'iterazione e, se si raggiunge un orario specifico, chiamare un setTimeout per tornare nel coda per continuare l'iterazione ... spero che tu l'abbia capito :) - In pratica, salva la quantità X delle chiamate setTimout ne è necessaria solo una.

Visualizza il codice Artem Bargers sopra e dovresti ottenere il succo di ciò che propongo.

Problemi correlati