Die Vermeidung einer javascript-race-Bedingung
Hier ist das Szenario:
Meine Benutzer präsentiert ein raster, im Grunde eine abgespeckte version einer Tabellenkalkulation. Dort sind Textfelder, die in jeder Zeile im raster. Wenn Sie ändern einen Wert in eine textbox, ich bin Validierung durchführen, die auf Ihrer Eingabe, Aktualisierung der Sammlung, die ' s fahren mit dem Gitter, zieht die Zwischensummen auf der Seite. Dies alles erfolgt durch das OnChange-Ereignis für jedes Textfeld.
Wenn Sie klicken Sie auf die Schaltfläche "Speichern", ich bin mit der Schaltfläche OnClick-Ereignis um einige abschließende Validierung auf die Beträge, und senden Sie dann Ihre gesamte Eingabe zu einem web-service zu speichern.
Zumindest ist das, was passiert, wenn Sie die tab durch das Formular auf den Submit-button.
Das problem ist, wenn Sie einen Wert eingeben, dann klicken Sie sofort auf die Schaltfläche speichern, SaveForm() beginnt mit der Ausführung vor UserInputChanged() beendet -- eine race-Bedingung. Mein code nicht verwenden, setTimeout, aber ich versuche zu simulieren, die träge UserInputChanged Validierung code:
<!-- snip -->
<script>
var amount = null;
var currentControl = null;
function UserInputChanged(control) {
currentControl = control;
//use setTimeout to simulate slow validation code (production code does not use setTimeout)
setTimeout("ValidateAmount()", 100);
}
function SaveForm() {
//call web service to save value
document.getElementById("SavedAmount").innerHTML = amount;
}
function ValidateAmount() {
//various validationey functions here
amount = currentControl.value; //save value to collection
document.getElementById("Subtotal").innerHTML = amount; //update subtotals
}
</script>
<!-- snip -->
Amount: <input type="text" id="UserInputValue" onchange="UserInputChanged(this);" /> <br />
Subtotal: <span id="Subtotal"></span> <br />
<input type="button" onclick="SaveForm();" value="Save" /> <br /><br />
Saved amount: <span id="SavedAmount"></span>
<!-- snip -->
Ich glaube nicht, ich kann Geschwindigkeit bis die Validierung der code-es ist ziemlich leicht, aber offenbar langsam genug, dass code versucht, um den Webdienst aufzurufen, bevor die Validierung abgeschlossen ist.
Auf meinem Rechner, ~95ms ist die Magische Zahl unterscheiden, ob der Validierungs-code wird ausgeführt, bevor das speichern-code beginnt. Dieser kann höher oder niedriger je nach Rechner-Geschwindigkeit.
Hat jemand irgendwelche Ideen, wie man diesem Zustand? Ein Mitarbeiter hat vorgeschlagen, eine semaphore, während der Validierungs-code ausgeführt wird und eine busy-loop in den save-code zu warten, bis die semaphore entriegelt-aber ich möchte vermeiden, mit jeder Art von busy-Schleife in meinem code.
InformationsquelleAutor der Frage Jeremy Frey | 2008-12-03
Du musst angemeldet sein, um einen Kommentar abzugeben.
Verwendung der semaphore (nennen wir es StillNeedsValidating). wenn die SaveForm Funktion sieht die StillNeedsValidating semaphore ist, haben es aktiviert einen zweiten semaphor seiner eigenen (ich nenne FormNeedsSaving hier) und zurück. Wenn die überprüfung die Funktion beendet, wenn der FormNeedsSaving semaphore ist, ruft es die SaveForm Funktion auf seine eigene.
In jankcode;
InformationsquelleAutor der Antwort zaratustra
Deaktivieren Sie die speichern-Taste während der Validierung.
Deaktiviert als erstes die Validierung und re-aktivieren, wie es endet.
z.B.
und
Müssen Sie anpassen, wenn Sie entfernen Sie die setTimeout und machen die überprüfung einer Funktion, aber es sei denn, Ihre Benutzer haben übermenschliche Reflexe, Sie sollten gut zu gehen.
InformationsquelleAutor der Antwort Andrew Rollings
Ich denke, dass den timeout verursacht dein problem ist... wenn die, die gehen, um einfache code (keine asynchronen AJAX-Aufrufe, timeouts etc) dann glaube ich nicht, dass SaveForm werden ausgeführt, bevor UserInputChanged abgeschlossen.
InformationsquelleAutor der Antwort Greg
Einer semaphore oder mutex ist wahrscheinlich der beste Weg zu gehen, aber anstelle von einem busy-loop, verwenden Sie einfach ein
setTimeout()
zu simulieren, die ein thread schlafen. Wie diese:InformationsquelleAutor der Antwort Excel Kobayashi
Könnte man die Einrichtung eines wiederkehrenden Funktion, die überwacht den Status des gesamten grid-und wirft ein Ereignis, das angibt, ob das gesamte Netz gültig ist oder nicht.
Ihre "Formular senden" - Schaltfläche aktivieren bzw. deaktivieren Sie basiert selbst auf diesen status.
Oh, ich sehe eine ähnliche Reaktion jetzt - das funktioniert natürlich auch.
InformationsquelleAutor der Antwort neonski
Sie nicht über eine race condition, Wettlauf Bedingungen kann das nicht passieren in javascript, da javascript ist single-threaded, also 2 threads können nicht einander stören.
Dem Beispiel, das Sie geben, ist nicht ein sehr gutes Beispiel. Die setTimeout-Aufruf die aufgerufene Funktion in einer Warteschlange in der javascript-engine, und führen Sie es später. Wenn Sie klicken Sie auf die Schaltfläche speichern, mit der setTimeout-Funktion wird nicht aufgerufen werden, erst NACHDEM das speichern abgeschlossen ist.
Was ist wohl passiert in deinem javascript ist, dass das onClick-Ereignis aufgerufen wird, der javascript-engine, bevor das onChange-Ereignis aufgerufen wird.
Als Hinweis, beachten Sie, dass javascript ist single-threaded, es sei denn, Sie verwenden ein javascript-debugger (firebug, microsoft screipt debugger). Diese Programme abzufangen und den thread pausiert werden. Von diesem Punkt aus auf andere threads (entweder über Veranstaltungen, setTimeout-Aufrufe oder XMLHttp-Handler) kann dann laufen, so dass es scheint, dass javascript ausgeführt werden kann mehrere threads gleichzeitig.
InformationsquelleAutor der Antwort
Beim arbeiten mit asynchronen Datenquellen können Sie sicherlich von race-conditions, da der JavaScript-Prozess-thread weiter ausgeführt, Direktiven, hängt von den Daten ab, die noch nicht zurückgegeben, die von der remote-Datenquelle. Deshalb müssen wir die callback-Funktionen.
In deinem Beispiel, der Aufruf des Validierungs-code muss eine callback-Funktion, die können etwas tun, wenn die Validierung gibt.
Jedoch, wenn Sie etwas mit komplizierter Logik oder Sie versuchen zu beheben oder zu verbessern eine bestehende Serie von Rückrufen, können Sie die Nüsse gehen.
Das ist der Grund, ich habe die proto-q-Bibliothek: http://code.google.com/p/proto-q/
Check it out, wenn Sie tun eine Menge von dieser Art von Arbeit.
InformationsquelleAutor der Antwort AutoSponge