Ich habe Javascript-Funktion wie folgt:
function myFunction(number) {
var x=number;
...
... more initializations
//here need to wait until flag==true
while(flag==false)
{}
...
... do something
}
Das Problem ist, dass das Javascript in der Zeit steckt und mein Programm steckt. Meine Frage ist also, wie ich in der Mitte der Funktion warten kann, bis das Flag wahr ist, ohne "beschäftigt zu warten".
javascript
synchronization
ilay zeidman
quelle
quelle
jQuery.Deferred
,Q
,async
, ...Antworten:
Da Javascript in einem Browser ein einzelner Thread ist (mit Ausnahme von Webworkern, die hier nicht beteiligt sind) und ein Thread der Javascript-Ausführung vollständig ausgeführt wird, bevor ein anderer ausgeführt werden kann, lautet Ihre Aussage:
wird einfach für immer ausgeführt (oder bis sich der Browser über eine nicht reagierende Javascript-Schleife beschwert), die Seite scheint hängen zu bleiben und kein anderes Javascript kann jemals ausgeführt werden, sodass der Wert des Flags niemals geändert werden kann.
Für ein wenig mehr Erklärung ist Javascript eine ereignisgesteuerte Sprache . Das bedeutet, dass ein Teil von Javascript ausgeführt wird, bis die Kontrolle an den Interpreter zurückgegeben wird. Erst wenn es zum Interpreter zurückkehrt, ruft Javascript das nächste Ereignis aus der Ereigniswarteschlange ab und führt es aus.
Alle Dinge wie Timer und Netzwerkereignisse werden in der Ereigniswarteschlange ausgeführt. Wenn also ein Timer ausgelöst wird oder eine Netzwerkanforderung eintrifft, "unterbricht" er niemals das aktuell ausgeführte Javascript. Stattdessen wird ein Ereignis in die Javascript-Ereigniswarteschlange gestellt. Wenn das aktuell ausgeführte Javascript beendet ist, wird das nächste Ereignis aus der Ereigniswarteschlange gezogen und kann ausgeführt werden.
Wenn Sie also eine Endlosschleife wie z. B.
while(flag==false) {}
ausführen, wird das aktuell ausgeführte Javascript nie beendet, und daher wird das nächste Ereignis nie aus der Ereigniswarteschlange gezogen, und daher wird der Wert vonflag
nie geändert. Der Schlüssel hier ist, dass Javascript nicht Interrupt-gesteuert ist . Wenn ein Timer ausgelöst wird, wird das aktuell ausgeführte Javascript nicht unterbrochen, es wird kein anderes Javascript ausgeführt und das aktuell ausgeführte Javascript wird fortgesetzt. Es wird nur in die Ereigniswarteschlange gestellt und wartet, bis das aktuell ausgeführte Javascript fertig ist, damit es an die Reihe kommt.Was Sie tun müssen, ist zu überdenken, wie Ihr Code funktioniert, und einen anderen Weg zu finden, um den Code auszulösen, den Sie ausführen möchten, wenn der Code
flag
Wert ändert. Javascript ist als ereignisgesteuerte Sprache konzipiert. Sie müssen also herausfinden, an welchen Ereignissen Sie ein Interesse anmelden können, damit Sie entweder auf das Ereignis warten können, durch das sich das Flag möglicherweise ändert, und das Flag für dieses Ereignis untersuchen oder Ihr eigenes Ereignis auslösen können Unabhängig davon, welcher Code das Flag ändert oder Sie eine Rückruffunktion implementieren können, kann jeder Code, der dieses Flag ändert, Ihren Rückruf aufrufen, wenn der Code, der für die Änderung des Flag-Werts verantwortlich ist, seinen Wert in ändert. Ertrue
ruft lediglich die Rückruffunktion und damit Ihren Code auf das will laufen, wenn das Flag gesetzt wirdtrue
wird zur richtigen Zeit laufen. Dies ist viel, viel effizienter als der Versuch, den Flag-Wert ständig mit einem Timer zu überprüfen.quelle
Javascript ist Single-Threaded, daher das Seitenblockierungsverhalten. Sie können den von anderen vorgeschlagenen Ansatz des verzögerten Versprechens verwenden, aber der grundlegendste Weg wäre die Verwendung
window.setTimeout
. Z.BHier ist ein gutes Tutorial mit weiteren Erklärungen: Tutorial
BEARBEITEN
Wie andere betonten, besteht der beste Weg darin, Ihren Code neu zu strukturieren, um Rückrufe zu verwenden. Diese Antwort sollte Ihnen jedoch eine Vorstellung davon geben, wie Sie ein asynchrones Verhalten mit "simulieren" können
window.setTimeout
.quelle
Verwenden:
quelle
Lösung mit Promise , async \ await und EventEmitter, die es ermöglicht, sofort auf Flaggenwechsel ohne Schleifen zu reagieren
EventEmitter
ist im Knoten eingebaut. Im Browser müssen Sie es selbst einbinden, beispielsweise mit diesem Paket: https://www.npmjs.com/package/eventemitter3quelle
ES6 mit Async / Await,
quelle
Mit Ecma Script 2017 können Sie async-await und while zusammen verwenden, um dies zu tun. Und während das Programm nicht abstürzt oder sperrt, ist selbst eine Variable niemals wahr
quelle
Moderne Lösung mit Promise
myFunction()
in der ursprünglichen Frage kann wie folgt geändert werdenWo
until()
ist diese Dienstprogrammfunktion?Einige Verweise auf asynchrone / warten- und Pfeilfunktionen befinden sich in einem ähnlichen Beitrag: https://stackoverflow.com/a/52652681/209794
quelle
Zum Durchlaufen von ($ .each) Objekten und Ausführen einer länger laufenden Operation (die verschachtelte Ajax-Synchronisierungsaufrufe enthält) für jedes Objekt:
Ich habe zuerst einen Brauch festgelegt
done=false
Eigenschaft für jede festgelegt.Stellen Sie dann in einer rekursiven Funktion jede ein
done=true
und verwenden Sie sie weitersetTimeout
. (Diese Operation soll alle anderen Benutzeroberflächen stoppen, einen Fortschrittsbalken anzeigen und alle anderen Verwendungszwecke blockieren, damit ich mir die Synchronisierungsaufrufe verziehen kann.)quelle
Ähnlich wie bei Lightbeards Antwort verwende ich den folgenden Ansatz
quelle
Ich habe versucht, den @ Kiran-Ansatz wie folgt zu verwenden:
(Framework, das ich benutze, zwingt mich, Funktionen auf diese Weise zu definieren). Aber ohne Erfolg, denn wenn die Ausführung zum zweiten Mal in die checkFlag-Funktion kommt,
this
ist dies nicht mein ObjektWindow
. Also habe ich mit dem Code unten fertigquelle
Verwenden von nicht blockierendem Javascript mit der EventTarget-API
In meinem Beispiel muss ich auf einen Rückruf warten, bevor ich ihn verwenden kann. Ich habe keine Ahnung, wann dieser Rückruf eingestellt ist. Es kann vor oder nach der Ausführung sein. Und ich muss es möglicherweise mehrmals aufrufen (alles asynchron)
quelle
Es gibt ein Knotenpaket, das
delay
sehr einfach zu bedienen istquelle
Ich habe hier einen Ansatz in Anlehnung an die Callback-Lösungen gewählt, aber versucht, ihn etwas allgemeiner zu gestalten. Die Idee ist, dass Sie Funktionen hinzufügen, die Sie ausführen müssen, nachdem sich etwas in einer Warteschlange geändert hat. Wenn das passiert, durchlaufen Sie die Warteschlange, rufen die Funktionen auf und leeren die Warteschlange.
Funktion zur Warteschlange hinzufügen:
Führen Sie die Warteschlange aus und leeren Sie sie:
Und wenn Sie _addToQueue aufrufen, möchten Sie den Rückruf umbrechen:
Wenn Sie die Bedingung erfüllt haben, rufen Sie an
_runQueue()
Dies war nützlich für mich, da ich mehrere Dinge hatte, die unter denselben Bedingungen warten mussten. Und es entkoppelt die Erkennung der Bedingung von allem, was ausgeführt werden muss, wenn diese Bedingung getroffen wird.
quelle
quelle
In meinem Beispiel protokolliere ich jede Sekunde einen neuen Zählerwert:
quelle
Wenn Sie Folgendes verwenden dürfen: In
async/await
Ihrem Code können Sie Folgendes ausprobieren:Demo hier: https://stackblitz.com/edit/typescript-bgtnhj?file=index.ts
Kopieren / Einfügen auf der Konsole :
goahead = true
.quelle