Este artículo está dirigido a Personen que empiezan con codificación asíncrona en JavaScript para que podamos mantener las cosas simples evitando palabras grandes, funciones de flecha, plantillas literales, etc.
Rückrufe Es ist eines der am häufigsten verwendeten Konzepte des modernen funktionalen Javascript und wenn Sie es jemals verwendet haben jQuery, du hast wohl schon benutzt Rückrufe ohne es zu wissen.
Was sind Rückruffunktionen?
EIN Rückruffunktion Im einfachsten Sinne ist es eine Funktion, die als Parameter an eine andere Funktion übergeben wird. Das Rückruffunktion Es wird innerhalb der Funktion ausgeführt, in der es übergeben wird, und das Endergebnis wird an den Aufrufer zurückgegeben.
Einfache Wahrheit? Jetzt werden wir eine Rückruffunktion implementieren, um Leveling-Ergebnisse in einem imaginären Spiel zu erhalten.
// levelOne () wird als Funktion höherer Ordnung bezeichnet, // weil es eine andere Funktion als Parameter akzeptiert. Funktion levelOne (Wert, Rückruf) {var newScore = Wert + 5; Rückruf (newScore); } // Beachten Sie, dass es nicht zwingend erforderlich ist, die Rückruffunktion (Zeile #3) als Rückruf zu bezeichnen, sie wird jedoch nur zum besseren Verständnis so benannt. Funktion startGame () {var currentScore = 5; console.log ('Spiel gestartet! Aktuelle Punktzahl ist' + aktuellerScore); // Hier ist der zweite Parameter, den wir an levelOne übergeben, die Rückruffunktion, dh eine Funktion, die als Parameter übergeben wird. levelOne (currentScore, function (levelOneReturnedValue) {console.log ('Level 1 erreicht! Neue Punktzahl ist' + levelOneReturnedValue);}); } Spiel beginnen ();
Einmal in der Funktion Spiel beginnen (), Wir nennen die Funktion Level eins () mit Parametern wie Momentaner Punktestand und unsere Rolle Rückrufen ().
Wenn wir anrufen Level eins () im Rahmen der Funktion Spiel beginnen (), asynchron führt JavaScript die Funktion aus Level eins () und der Haupt-Thread fährt mit dem verbleibenden Teil unseres Codes fort.
Esto significa que podemos hacer todo tipo de operaciones como obtener datos de una API, hacer cálculos matemáticos, etc., todo lo cual puede consumir mucho tiempo y, por lo tanto, no estaremos bloqueando nuestro hilo principal para ello. Una vez que la Funktion (levelOne ()) Wenn Sie mit Ihren Operationen fertig sind, können Sie die Funktion ausführen Rückrufen das haben wir vorher durchgemacht.
Esta es una característica muy útil de la Programmierung de funciones, ya que las Rückrufe nos permiten manejar el código asincrónicamente sin tener que esperar una respuesta. Por ejemplo, puede hacer una llamada de ajax a un Server lento con una función de Rückrufen und vergessen Sie es vollständig und fahren Sie mit dem verbleibenden Code fort. Sobald dieser Ajax-Anruf aufgelöst ist, wird die Rückruffunktion automatisch ausgeführt.
Aber die Rückrufe Sie können unangenehm werden, wenn in einer Kette mehrere Rückrufebenen ausgeführt werden müssen. Nehmen wir das obige Beispiel und fügen unserem Spiel einige weitere Level hinzu.
Funktion levelOne (Wert, Rückruf) {var newScore = Wert + 5; Rückruf (newScore); } function levelTwo (Wert, Rückruf) {var newScore = Wert + 10; Rückruf (newScore); } function levelThree (Wert, Rückruf) {var newScore = Wert + 30; Rückruf (newScore); } // Beachten Sie, dass es beim Aufrufen von levelOne (), levelTwo () oder levelTree () nicht erforderlich ist, die Rückruffunktion als Rückruf zu bezeichnen, da sie beliebig benannt werden kann. Funktion startGame () {var currentScore = 5; console.log ('Spiel gestartet! Aktuelle Punktzahl ist' + currentScore); levelOne (currentScore, function (levelOneReturnedValue) {console.log ('Level 1 erreicht! Neue Punktzahl ist' + levelOneReturnedValue); levelTwo (levelOneReturnedValue); function (levelTwoReturnedValue) {console.log (Level 2 erreicht! Neue Punktzahl ist '+ levelTwoReturned ; levelThree (levelTwoReturnedValue, function (levelThreeReturnedValue) {console.log ('Stufe drei erreicht! Neue Punktzahl ist' + levelThreeReturnedValue);});});}); } Spiel beginnen ();
Warten Sie, was ist gerade passiert? Wir haben zwei neue Funktionen für die Ebenenlogik hinzugefügt: levelTwo () y levelThree (). Innerhalb Rückruf von levelOne (Zeile #22), Funktion aufrufen levelTwo () mit einer Funktion von Rückrufen und das Ergebnis von Rückrufen von Level eins. Und das Gleiche wird für die Funktion der Stufe drei wiederholt.
Stellen Sie sich nun vor, wie dieser Code aussehen wird, wenn wir dieselbe Logik für weitere 10 Ebenen implementieren. Bist du schon in Panik? Nun, das tue ich! Mit zunehmender Anzahl verschachtelter Rückruffunktionen wird der Code schwieriger zu lesen und noch schwieriger zu debuggen.
Dies wird oft liebevoll als bezeichnet Rückruf Hölle. Gibt es einen Ausweg aus dieser Rückrufhölle?
Ich verspreche Ihnen, dass es einen besseren Weg gibt
Javascript begann zu unterstützen Versprechen von ES6. Versprechen sind im Grunde genommen Objekte, die den Abschluss (oder den Fehler) einer asynchronen Operation und den daraus resultierenden Wert darstellen.
Versuchen wir jetzt, unser Beispiel für einen Höllenrückruf mit Versprechungen neu zu schreiben.
Funktion levelOne (Wert) {var Versprechen, newScore = Wert + 5; Rückgabeversprechen = neues Versprechen (Funktion (Auflösung) {Auflösung (newScore);}); } function levelTwo (value) {var versprechen, newScore = value + 10; Rückgabeversprechen = neues Versprechen (Funktion (Auflösung) {Auflösung (newScore);}); } function levelThree (value) {var versprechen, newScore = value + 30; Rückgabeversprechen = neues Versprechen (Funktion (Auflösung) {Auflösung (newScore);}); } var startGame = neues Versprechen (Funktion (auflösen, ablehnen) {var currentScore = 5; console.log ('Spiel gestartet! Aktuelle Punktzahl ist' + currentScore); auflösen (currentScore);}); // Die Antwort von startGame wird automatisch an die Funktion im nachfolgenden Dialogfenster übergeben. startGame.then (levelOne) .then (function (result) {// Der Wert des Ergebnisses ist das Versprechen, das von der levelOne-Funktion console.log zurückgegeben wurde ('Sie haben Level 1 erreicht! Die neue Punktzahl ist' + result); return Ergebnis;}) .then (levelTwo) .then (Funktion (Ergebnis) {console.log ('Sie haben Level 2 erreicht! Die neue Punktzahl ist' + Ergebnis); Ergebnis zurückgeben;}) .then (levelThree) .then ( function (result) {console.log ('Du hast Level 3 erreicht! Die neue Punktzahl ist' + result);});
Wir haben unsere Ebenenfunktionen (Eins / Zwei / Drei) neu geschrieben, um die Rückrufe aus dem Funktionsparameter zu entfernen, und anstatt die darin enthaltene Rückruffunktion aufzurufen, haben wir sie durch Versprechen ersetzt.
Sobald es gelöst ist Spiel beginnen, Wir können einfach eine Methode aufrufen .dann () darauf und behandeln das Ergebnis. Wir können mehrere Versprechen nacheinander verketten .dann () .
Esto hace que todo el código Sein mucho más legible y más fácil de entender en términos de lo que está sucediendo, y luego de lo que sucede a continuación y así sucesivamente.
Der tiefe Grund, warum Versprechen oft besser sind, ist, dass sie komponierbarer sind, was bedeutet, dass das Kombinieren mehrerer Versprechen "einfach funktioniert", während das Kombinieren mehrerer Rückrufe oft nicht funktioniert.
Wenn wir einen einzigen Rückruf gegen ein einziges Versprechen haben, gibt es zwar keinen signifikanten Unterschied. Wenn Sie eine Million Rückrufe gegen eine Million Versprechen haben, sieht vielversprechender Code in der Regel viel besser aus.
Okay, wir sind der Callback-Hölle erfolgreich entkommen und haben unseren Code mit Versprechungen viel lesbarer gemacht. Aber was wäre, wenn ich Ihnen sagen würde, dass es eine Möglichkeit gibt, es sauberer und lesbarer zu machen?
(a) Warten Sie dafür
Async-wait wird seit ECMA2017 in Javascript unterstützt. Mit ihnen können Sie Code basierend auf Versprechungen schreiben, als wäre es synchroner Code, ohne jedoch den Hauptthread zu blockieren. Sie machen Ihren asynchronen Code weniger "intelligent" und besser lesbar.
Um ehrlich zu sein, sind Asynkrasien nichts anderes als syntaktischer Zucker zusätzlich zu Versprechungen, aber sie lassen asynchronen Code ein bisschen mehr wie synchronen Code aussehen und sich so verhalten, genau hier liegt ihre Macht.
Si utiliza la Stichwort Async antes de la definición de una función, puede utilizar la opción de espera dentro de la función. Cuando usted espera una promesa, la función se detiene de una manera que no bloquee hasta que se cumpla la promesa. Si la promesa se cumple, se recupera el valor. Si la promesa es rechazada, el valor rechazado es lanzado.
Lassen Sie uns nun sehen, wie unsere Spiellogik aussieht, wenn wir sie neu schreiben Async-erwartet.
Funktion levelOne (Wert) {var Versprechen, newScore = Wert + 5; Rückgabeversprechen = neues Versprechen (Funktion (Auflösung) {Auflösung (newScore);}); } function levelTwo (value) {var versprechen, newScore = value + 10; Rückgabeversprechen = neues Versprechen (Funktion (Auflösung) {Auflösung (newScore);}); } function levelThree (value) {var versprechen, newScore = value + 30; Rückgabeversprechen = neues Versprechen (Funktion (Auflösung) {Auflösung (newScore);}); } // Das asynchrone Schlüsselwort teilt der Javascript-Engine mit, dass jede Funktion in dieser Funktion, die das Schlüsselwort await enthält, als asynchroner Code behandelt werden soll und erst ausgeführt werden soll, nachdem diese Funktion aufgelöst wurde oder fehlschlägt.
asynchrone Funktion startGame () {var currentScore = 5; console.log ('Spiel gestartet! Aktuelle Punktzahl ist' + currentScore); currentScore = warte auf levelOne (currentScore); console.log ('Du hast Level Eins erreicht! Die neue Punktzahl ist' + currentScore); currentScore = warte auf levelTwo (currentScore); console.log ('Du hast Level Zwei erreicht! Die neue Punktzahl ist' + currentScore); currentScore = warte auf levelThree (currentScore); console.log (Du hast Level Drei erreicht! Die neue Punktzahl ist '+ currentScore); } Spiel beginnen ();
Sofort wird unser Code viel lesbarer, aber es gibt noch mehr zu tun Async-warten.
Die Fehlerbehandlung ist eine der wichtigsten Funktionen von Async-await, die auffällt. Wir können endlich sowohl synchrone als auch asynchrone Fehler mit derselben Konstruktion mit try and catches behandeln, was mit Versprechungen ein Schmerz war, ohne try-catch-Blöcke zu duplizieren.
Die nächstbeste Verbesserung in der Welt der guten alten Versprechen ist das Code-Debugging. Wenn wir Versprechen schreiben, die auf Pfeilfunktionen basieren, können wir innerhalb unserer Pfeilfunktionen keine Haltepunkte setzen, daher ist das Debuggen manchmal schwierig. Bei asynchronen Wartezeiten ist das Debuggen jedoch wie ein synchrones Code-Snippet