Domanda

Ho un'applicazione web in cui è presente un timer che esegue costantemente il conto alla rovescia.Nel frattempo, il client controlla frequentemente con il server per vedere se è stato aggiunto più tempo al timer.Il codice è simile a questo:

function tick() {
    // This function is called once every second
    time -= 1;
    redisplay(time);
};
function update(newtime) {
    // This function is called whenever the ajax request
    // to the server yields a new time
    time = newtime;
};

Ovviamente è un po’ più complesso di così, ma puoi vedere la condizione di razza intrinseca.Cosa succede se l'aggiornamento e la funzione di spunta tentano entrambi di modificare time allo stesso tempo?

Francamente, non conosco abbastanza Javascript per capire come affrontare questo tipo di problema di concorrenza:esiste un modo semplice per farlo o, in caso contrario, qualcuno può indicarmi risorse in cui posso imparare di più?

Grazie.

È stato utile?

Soluzione

Non hai una condizione di competizione, perché Javascript non viene eseguito contemporaneamente.

Ogni volta che viene attivata una richiamata da un'operazione asincrona (AJAX, setTimeout, ecc.), l'esecuzione del callback deve terminare prima che possa essere chiamato un altro callback da un'altra operazione asincrona.Quindi se update() è in esecuzione, nessun altro Javascript lo è.Una volta update() termina, è possibile attivare altre richiamate da operazioni asincrone (ad esempio, tick()).È interessante notare che questo è anche il motivo setTimeout e non è garantito che i suoi simili vengano eseguiti nel momento preciso in cui viene raggiunto il timeout:qualche altro JavaScript potrebbe bloccare l'esecuzione del callback.

Guardare http://ejohn.org/blog/how-javascript-timers-work/ per alcune buone informazioni su come funziona tutto questo.

Altri suggerimenti

Javascript è a thread singolo. Non v'è alcuna condizione di competizione. Non c'è modo in JavaScript per le due linee time = newtime; e time -= 1; a sovrapporsi durante l'esecuzione. Infatti, le due funzioni sono garantiti non sovrapporsi. Uno di loro verrà eseguito e poi l'altra verrà eseguito.

mi sbagliavo: questo non risolve il problema! (Spiegazione dopo il codice)

NEWTIME = false;
function tick() {
    // This function is called once every second
    if (NEWTIME) {
        time = NEWTIME;
        NEWTIME = false;
    }
    time -= 1;
    redisplay(time);
};
function update(newtime) {
    // This function is called whenever the ajax request
    // to the server yields a new time
    NEWTIME = newtime;
};

Il problema di questa soluzione sbagliata è che facendo in questo modo basta spostare il problema da race condition time variabile NEWTIME variabile.

Basta pensare questo: l'esecuzione di tick raggiunge ed esegue il time = NEWTIME; linea di oggi, prima di continuare, di aggiornamento e di ottenere chiamato NEWTIME ottiene un valore di X. Ora esecuzione tick continua ad eseguire NEWTIME = false;. In questo modo hai perso il valore X di NEWTIME e quindi l'effetto di un aggiornamento () chiamata!

Il problema ha bisogno di alcuni semafori. Lo faccio molto per l'invio di Ajax dopo conclusione di quello precedente. Il tuo caso è un po 'allo stesso modo;)

Prova qualcosa di simile. Si deve ignorare tutti i tentativi per diminuire il tempo che si scontrano con AJAX callback.

window.TimeKeeper = new function(){
this.time=0; //initial value, whatever
this.isopen=true;

this.decrement = function(){ 
 if(this.isopen){
  this.time--;
  redisplay(this.time);
  }
 }
this.set = function(val){
 if(this.isopen){
  this.isopen=false;
  this.time=val;
  this.isopen=true;
  } else {
  //another AJAX callback is modifying time. 
   //You can enqueue current value and put it later
  }
 }

}

function tick() {
    TimeKeeper.decrement();

};
function update(newtime) {
    TimeKeeper.set(newtime);
};

Una cosa di più - il setTimeout funziona come un nuovo thread e mi aspetto che i browser fanno la sincronizzazione accesso mem, quindi potrebbe essere sufficiente per controllare se il valore non è cresciuto prima di decremento. Ma la soluzione di cui sopra è più flessibile e sicuro.

E un piccolo suggerimento - evitare l'esecuzione di query con AJAX troppo spesso - può causare ulteriori problemi - come le richieste provenienti in ordine diverso da quello inviato, e l'utilizzo della memoria firefox costruendo un sacco su troppo ajax un minuto;)

Fino a quando si aggiungono alcuni secondi per il tempo attuale si dovrebbe andare bene.

Invece di fare time = newtime; provare time += newtime; In questo modo non si perde la seconda siete preoccupati.

Ancora, si sta solo perdendo un secondo nel peggiore dei casi.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top