ajax Concurrency
-
21-09-2019 - |
Frage
ich eine Web-Anwendung, in der es einen Timer, der ständig nach unten zählt. Inzwischen hat der Kunde häufig überprüft mit dem Server zu sehen, wenn mehr Zeit, um den Timer hinzugefügt wurde. Der Code sieht etwa so aus:
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;
};
Es ist, natürlich, ein wenig komplexer als das, aber man kann die inhärente Race-Bedingung sehen. Was passiert, wenn das Update und die Zecke Funktion sind beide time
gleichzeitig zu ändern versuchen?
Ehrlich gesagt, ich weiß es nicht annähernd genug, um Javascript zu verstehen, wie mit dieser Art von Gleichzeitigkeit Thema befassen: Gibt es eine einfache Möglichkeit, dies zu tun, oder wenn nicht, kann jemand Punkt mich auf Ressourcen, wo ich mehr lernen kann?
Danke.
Lösung
Sie haben nicht eine Race-Bedingung, weil Javascript nicht gleichzeitig ausgeführt werden.
Jedes Mal, wenn ein Rückruf von einer Asynchron-Operation ausgelöst wird (AJAX, setTimeout
, usw.), muss dieser Rückruf vor einem anderen Rückruf von einem anderen asynchronen Betrieb Ausführung beenden kann aufgerufen werden. Also, wenn update()
läuft, ist kein anderer Javascript. Sobald update()
abgeschlossen ist, können andere Rückrufe von Asynchron-Operationen ausgelöst werden (zB tick()
). Interessanterweise ist diese auch deshalb setTimeout
und seine Konsorten nicht das Timeout in dem Augenblick zur Ausführung garantiert erreicht ist. Einige andere JavaScript, um den Rückrufs Hinrichtung blockiert sein könnten
Schauen Sie sich http://ejohn.org/blog/how-javascript-timers -Arbeit / für ein paar gute Informationen darüber, wie all dies funktioniert.
Andere Tipps
ist Javascript single threaded. Es gibt keine Race-Bedingung. Es gibt keine Möglichkeit in Javascript für die beiden Linien time = newtime;
und time -= 1;
zu Überschneidungen bei der Ausführung. In der Tat sind die beiden Funktionen garantiert nicht zu überlappen. Einer von ihnen laufen und dann in die andere laufen.
Ich war falsch: dies das Problem nicht lösen! (Explaination nach dem Code)
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;
};
Das Problem mit dieser falschen Lösung besteht darin, dass auf diese Weise tun Sie gerade die Race-Bedingung Ausgabe von variablen time
auf variable NEWTIME
bewegen.
Man denke nur an das: die Ausführung von tick
erreicht und führt die Linie time = NEWTIME;
jetzt, bevor Sie fortfahren, zu aktualisieren aufgerufen und NEWTIME
erhält einen Wert X
. Jetzt tick Ausführung fortgesetzt Ausführung NEWTIME = false;
. Auf diese Weise können die X
Wert von NEWTIME
verloren haben und so die Wirkung eines Updates () -Aufruf!
Das Problem braucht einige Semaphore. Ich tun, dass viel für Ajax nach vorherigen Ausführungen zu senden. Ihr Fall ist ein wenig gleich;)
Versuchen Sie so etwas. Es sollte alle Versuche Abnahmedauer, dass kollidieren mit AJAX Callback ignorieren.
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);
};
Eine weitere Sache - die setTimeout funktioniert wie ein neuer Thread, und ich würde erwarten, dass Browser die Synchronisierungs mem Zugang zu tun, so dass es genug sein könnte, um zu überprüfen, ob der Wert nicht wuchs nicht vor seinem Erniedrigen. Aber die obige Lösung ist flexibler und sicherer.
Und ein kleiner Tipp - avoid anfragende mit AJAX zu oft - es zusätzliche Probleme verursachen kann - wie Anfragen kommen wieder in einer anderen Reihenfolge als abgeschickt, und Firefox Speicherverbrauch viel zu viel Ajax Minute Aufbau;)
Solange Sie noch einige Sekunden, um Ihnen aktuelle Zeit hinzufügen Sie sollten in Ordnung sein.
Statt time = newtime;
Versuch time += newtime;
tun diese Weise werden Sie die zweite nicht verlieren Sie besorgt über.
Dennoch sind Sie nur eine Sekunde, im schlimmsten Fall zu verlieren.