Erstens ist dies ein sehr spezifischer Fall, bei dem es absichtlich falsch gemacht wird, einen asynchronen Aufruf in eine sehr synchrone Codebasis nachzurüsten, die viele tausend Zeilen lang ist und die Zeit derzeit nicht die Möglichkeit bietet, die Änderungen an "do" vorzunehmen es richtig." Es tut jeder Faser meines Seins weh, aber Realität und Ideale greifen oft nicht ineinander. Ich weiß, das ist scheiße.
OK, das aus dem Weg, wie mache ich es so, dass ich:
function doSomething() {
var data;
function callBack(d) {
data = d;
}
myAsynchronousCall(param1, callBack);
// block here and return data when the callback is finished
return data;
}
Die Beispiele (oder deren Fehlen) verwenden alle Bibliotheken und / oder Compiler, die beide für diese Lösung nicht geeignet sind. Ich brauche ein konkretes Beispiel, wie man es blockiert (z. B. die Funktion doSomething NICHT verlassen, bis der Rückruf aufgerufen wird), OHNE die Benutzeroberfläche einzufrieren. Wenn so etwas in JS möglich ist.
quelle
Antworten:
OK. aber du solltest es wirklich richtig machen ... oder was auch immer
Nein, es ist unmöglich, das laufende JavaScript zu blockieren, ohne die Benutzeroberfläche zu blockieren.
Angesichts des Mangels an Informationen ist es schwierig, eine Lösung anzubieten. Eine Möglichkeit besteht jedoch darin, dass die aufrufende Funktion eine Abfrage durchführt, um eine globale Variable zu überprüfen, und dann den Rückruf
data
auf global setzt.All dies setzt voraus, dass Sie Änderungen vornehmen können
doSomething()
. Ich weiß nicht, ob das in den Karten ist.Wenn es geändert werden kann, weiß ich nicht, warum Sie nicht einfach einen Rückruf an
doSomething()
den anderen Rückruf weiterleiten würden, aber ich höre besser auf, bevor ich in Schwierigkeiten gerate. ;)Oh, was zum Teufel. Sie haben ein Beispiel gegeben, das darauf hinweist, dass es richtig gemacht werden kann, also werde ich diese Lösung zeigen ...
Da Ihr Beispiel einen Rückruf enthält, der an den asynchronen Aufruf übergeben wird, besteht der richtige Weg darin, eine Funktion zu übergeben
doSomething()
, die vom Rückruf aufgerufen werden soll.Wenn dies das einzige ist, was der Rückruf bewirkt, würden Sie natürlich
func
direkt weitergeben ...quelle
callback
Funktion an diemyAsynchronousCall
Funktion, die ihre asynchronen Aufgaben ausführt und den Rückruf aufruft, wenn sie abgeschlossen ist. Hier ist eine Demo.Async-Funktionen , eine Funktion in ES2017 , sorgen dafür , dass Async-Code mithilfe von Versprechungen (einer bestimmten Form von Async-Code) und dem
await
Schlüsselwort synchronisiert aussieht . Beachten Sie auch in den Codebeispielen unter dem Schlüsselwortasync
vor demfunction
Schlüsselwort, das eine asynchrone / wartende Funktion kennzeichnet. Dasawait
Schlüsselwort funktioniert nicht, ohne in einer Funktion zu sein, die mit demasync
Schlüsselwort voreingestellt ist . Da es derzeit keine Ausnahme gibt, bedeutet dies, dass keine Wartezeiten der obersten Ebene funktionieren (Wartezeiten der obersten Ebene bedeuten ein Warten außerhalb einer Funktion). Es gibt jedoch einen Vorschlag für die oberste Ebeneawait
.ES2017 wurde am 27. Juni 2017 als Standard für JavaScript ratifiziert (dh finalisiert). Async await funktioniert möglicherweise bereits in Ihrem Browser. Andernfalls können Sie die Funktionalität weiterhin mit einem Javascript-Transpiler wie babel oder traceur verwenden . Chrome 55 bietet volle Unterstützung für asynchrone Funktionen. Wenn Sie also einen neueren Browser haben, können Sie möglicherweise den folgenden Code ausprobieren.
Siehe kangax des es2017 Kompatibilitätstabelle für Browser - Kompatibilität.
Hier ist ein Beispiel für eine asynchrone Wartefunktion,
doAsync
die drei Pausen von einer Sekunde benötigt und die Zeitdifferenz nach jeder Pause ab der Startzeit ausgibt:Wenn das Schlüsselwort await vor einem Versprechungswert steht (in diesem Fall ist der Versprechenswert der von der Funktion doSomethingAsync zurückgegebene Wert), pausiert das Schlüsselwort await die Ausführung des Funktionsaufrufs, hält jedoch keine anderen Funktionen an und fährt fort Ausführen von anderem Code, bis das Versprechen aufgelöst ist. Nachdem das Versprechen aufgelöst wurde, wird der Wert des Versprechens ausgepackt, und Sie können sich vorstellen, dass der Ausdruck Warten und Versprechen jetzt durch diesen ausgepackten Wert ersetzt wird.
Da das Warten nur pausiert und wartet, wird dann ein Wert entpackt, bevor der Rest der Zeile ausgeführt wird. Sie können ihn für Schleifen und interne Funktionsaufrufe wie im folgenden Beispiel verwenden, in dem die in einem Array erwarteten Zeitunterschiede erfasst und das Array ausgedruckt werden.
Die asynchrone Funktion selbst gibt ein Versprechen zurück, sodass Sie dieses als Versprechen mit Verkettung verwenden können, wie ich es über oder innerhalb einer anderen asynchronen Wartefunktion tue.
Die obige Funktion wartet auf jede Antwort, bevor eine weitere Anfrage gesendet wird . Wenn Sie die Anfragen gleichzeitig senden möchten, können Sie Promise.all verwenden .
Wenn das Versprechen möglicherweise abgelehnt wird, können Sie es in einen Try-Catch einschließen oder den Try-Catch überspringen und den Fehler auf den Catch-Aufruf der asynchronen / wait-Funktionen übertragen. Sie sollten darauf achten, Versprechungsfehler nicht unbehandelt zu lassen, insbesondere in Node.js. Im Folgenden finden Sie einige Beispiele, die zeigen, wie Fehler funktionieren.
Wenn du hierher gehst Sie die fertigen Vorschläge für kommende ECMAScript-Versionen.
Eine Alternative dazu, die nur mit ES2015 (ES6) verwendet werden kann, ist die Verwendung einer speziellen Funktion, die eine Generatorfunktion umschließt. Generatorfunktionen verfügen über ein Yield-Schlüsselwort, mit dem das Schlüsselwort await mit einer umgebenden Funktion repliziert werden kann. Das Yield-Schlüsselwort und die Generatorfunktion sind viel allgemeiner und können viel mehr als das, was die asynchrone Wartefunktion tut. Wenn Sie einen Generatorfunktions-Wrapper benötigen , der zum Replizieren von asynchronem Warten verwendet werden kann, würde ich co.js überprüfen . Übrigens, die Funktion von co, ähnlich wie die asynchronen Wartefunktionen, gibt ein Versprechen zurück. Ehrlich gesagt ist die Browserkompatibilität zu diesem Zeitpunkt sowohl für Generatorfunktionen als auch für Async-Funktionen ungefähr gleich. Wenn Sie also nur die Async-Wait-Funktion wünschen, sollten Sie Async-Funktionen ohne co.js verwenden.
Die Browserunterstützung ist jetzt für Async-Funktionen (Stand 2017) in allen gängigen Browsern (Chrome, Safari und Edge) mit Ausnahme des IE ziemlich gut.
quelle
Schauen Sie sich JQuery Promises an:
http://api.jquery.com/promise/
http://api.jquery.com/jQuery.when/
http://api.jquery.com/deferred.promise/
Refactor den Code:
quelle
dfd.notify(data)
zudfd.resolve(data)
Es gibt eine nette Problemumgehung unter http://taskjs.org/
Es werden Generatoren verwendet, die für Javascript neu sind. Daher wird es derzeit von den meisten Browsern nicht implementiert. Ich habe es in Firefox getestet und für mich ist es eine gute Möglichkeit, die asynchrone Funktion zu verpacken.
Hier ist Beispielcode aus dem Projekt GitHub
quelle
Sie können asynchrones JavaScript in NodeJS erzwingen, damit es mit sync-rpc synchron ist .
Es wird Ihre Benutzeroberfläche definitiv einfrieren, daher bin ich immer noch ein Neinsager, wenn es darum geht, ob es möglich ist, die Verknüpfung zu verwenden, die Sie benötigen. Es ist nicht möglich, den One And Only Thread in JavaScript auszusetzen, selbst wenn Sie ihn mit NodeJS manchmal blockieren können. Keine Rückrufe, Ereignisse oder asynchronen Daten können verarbeitet werden, bis Ihr Versprechen erfüllt ist. Wenn Sie als Leser also keine unvermeidbare Situation wie das OP haben (oder in meinem Fall ein verherrlichtes Shell-Skript ohne Rückrufe, Ereignisse usw. schreiben), TUN SIE DAS NICHT!
Aber so können Sie das machen:
./calling-file.js
./my-asynchronous-call.js
EINSCHRÄNKUNGEN:
Beides ist eine Folge der Art und Weise der
sync-rpc
Implementierung, nämlich durch Missbrauchrequire('child_process').spawnSync
:JSON.stringify
, sodass Funktionen und nicht aufzählbare Eigenschaften wie Prototypketten verloren gehen.quelle
Sie können es auch in Rückrufe konvertieren.
quelle
Was Sie wollen, ist jetzt tatsächlich möglich. Wenn Sie den asynchronen Code in einem Service Worker und den synchronen Code in einem Web Worker ausführen können, können Sie den Web Worker eine synchrone XHR an den Service Worker senden lassen, und während der Service Worker die asynchronen Aufgaben ausführt, den Web Worker Thread wird warten. Dies ist kein großartiger Ansatz, aber er könnte funktionieren.
quelle
Die Idee, die Sie erreichen möchten, kann ermöglicht werden, wenn Sie die Anforderungen ein wenig anpassen
Der folgende Code ist möglich, wenn Ihre Laufzeit die ES6-Spezifikation unterstützt.
Weitere Informationen zu asynchronen Funktionen
quelle
SyntaxError: await is only valid in async functions and async generators
. Ganz zu schweigen davon, dass param1 nicht definiert ist (und nicht einmal verwendet wird).