Ich habe JavaScript seit ein paar Jahren entwickelt und verstehe die Aufregung um Versprechen überhaupt nicht.
Alles, was ich tue, scheint sich zu ändern:
api(function(result){
api2(function(result2){
api3(function(result3){
// do work
});
});
});
Wofür ich sowieso eine Bibliothek wie Async verwenden könnte , mit so etwas wie:
api().then(function(result){
api2().then(function(result2){
api3().then(function(result3){
// do work
});
});
});
Welches ist mehr Code und weniger lesbar. Ich habe hier nichts gewonnen, es ist auch nicht plötzlich magisch "flach". Ganz zu schweigen davon, Dinge in Versprechen umwandeln zu müssen.
Also, was ist die große Aufregung um Versprechen hier?
Antworten:
Versprechen sind keine Rückrufe. Ein Versprechen repräsentiert das zukünftige Ergebnis einer asynchronen Operation . Wenn Sie sie so schreiben, wie Sie es tun, erhalten Sie natürlich wenig Nutzen. Wenn Sie sie jedoch so schreiben, wie sie verwendet werden sollen, können Sie asynchronen Code so schreiben, dass er synchronem Code ähnelt und viel einfacher zu befolgen ist:
Sicherlich nicht viel weniger Code, aber viel besser lesbar.
Dies ist jedoch nicht das Ende. Lassen Sie uns die wahren Vorteile entdecken: Was ist, wenn Sie in einem der Schritte nach Fehlern suchen möchten? Es wäre die Hölle, es mit Rückrufen zu tun, aber mit Versprechungen ist ein Kinderspiel:
So ziemlich das gleiche wie ein
try { ... } catch
Block.Noch besser:
Und noch besser: Was passiert , wenn diese drei Anrufe
api
,api2
,api3
könnte gleichzeitig ausgeführt werden (zB wenn sie AJAX Anrufe) , aber man benötigt für die drei warten? Ohne Versprechen sollten Sie eine Art Zähler erstellen müssen. Mit Versprechungen ist die Verwendung der ES6-Notation ein weiteres Kinderspiel und ziemlich ordentlich:Ich hoffe, Sie sehen Versprechen jetzt in einem neuen Licht.
quelle
api2
und asynchrone Operationen ausgeführt werdenapi3
? Würde der letzte.then
erst aufgerufen, wenn diese asynchronen Vorgänge abgeschlossen sind?Ja, Versprechen sind asynchrone Rückrufe. Sie können nichts tun, was Rückrufe nicht können, und Sie haben mit der Asynchronität dieselben Probleme wie mit einfachen Rückrufen.
Versprechen sind jedoch mehr als nur Rückrufe. Sie sind eine sehr mächtige Abstraktion, ermöglichen saubereren und besseren Funktionscode mit weniger fehleranfälligem Boilerplate.
Versprechen sind Objekte, die das Ergebnis einer einzelnen (asynchronen) Berechnung darstellen. Sie lösen dieses Ergebnis nur einmal auf. Es gibt ein paar Dinge, was dies bedeutet:
Versprechen implementieren ein Beobachtermuster:
return
ein Promise-Objekt erstellenVersprechen sind verkettbar ( monadisch , wenn Sie wollen ):
.then()
Methode verwenden. Es wird ein Rückruf benötigt, um mit dem ersten Ergebnis aufgerufen zu werden, und es wird ein Versprechen für das Ergebnis des Versprechens zurückgegeben, dass der Rückruf zurückkehrt.Klingt kompliziert? Zeit für ein Codebeispiel.
Das Abflachen ist nicht magisch, aber Sie können es leicht tun. Für Ihr stark verschachteltes Beispiel wäre das (nahe) Äquivalent
Wenn das Anzeigen des Codes dieser Methoden zum Verständnis beiträgt, finden Sie hier ein paar grundlegende Versprechen in wenigen Zeilen .
Die Promise-Abstraktion ermöglicht eine viel bessere Zusammensetzbarkeit von Funktionen. Neben der
then
Verkettung erstellt dieall
Funktion beispielsweise ein Versprechen für das kombinierte Ergebnis mehrerer parallel wartender Versprechen.Last but not least kommen Versprechen mit integrierter Fehlerbehandlung. Das Ergebnis der Berechnung könnte sein, dass das Versprechen entweder mit einem Wert erfüllt oder mit einem Grund abgelehnt wird . Alle Kompositionsfunktionen behandeln dies automatisch und verbreiten Fehler in Versprechensketten, sodass Sie sich nicht überall explizit darum kümmern müssen - im Gegensatz zu einer einfachen Rückrufimplementierung. Am Ende können Sie einen dedizierten Fehlerrückruf für alle aufgetretenen Ausnahmen hinzufügen.
Bei Bibliotheken mit guten Versprechen ist das eigentlich ziemlich trivial. Siehe Wie konvertiere ich eine vorhandene Rückruf-API in Versprechen?
quelle
.then(console.log)
, da console.log vom Konsolenkontext abhängt. Auf diese Weise wird ein unzulässiger Aufruffehler verursacht. Verwenden Sieconsole.log.bind(console)
oderx => console.log(x)
, um den Kontext zu binden.console
Methoden bereits gebunden sind. Und natürlich habe ich nur gesagt, dass beide Verschachtelungen genau das gleiche Verhalten haben, nicht dass eine von ihnen funktionieren würde :-PZusätzlich zu den bereits etablierten Antworten verwandeln sich Promises mit ES6-Pfeilfunktionen von einem bescheiden leuchtenden kleinen blauen Zwerg direkt in einen roten Riesen. Das ist im Begriff, in eine Supernova zu fallen:
Wie Oligofren betonte, benötigen Sie ohne Argumente zwischen API-Aufrufen überhaupt keine anonymen Wrapper-Funktionen:
Und schließlich, wenn Sie ein supermassereiches Schwarzes Loch erreichen möchten, können Sie auf Versprechen warten:
quelle
apiX
Methoden nicht verwenden, können Sie die Pfeilfunktionen auch ganz überspringen :api().then(api2).then(api3).then(r3 => console.log(r3))
.Zusätzlich zu den fantastischen Antworten oben können 2 weitere Punkte hinzugefügt werden:
1. Semantischer Unterschied:
Versprechen können bereits bei der Erstellung gelöst werden. Dies bedeutet, dass sie eher Bedingungen als Ereignisse garantieren . Wenn sie bereits aufgelöst sind, wird die an sie übergebene aufgelöste Funktion weiterhin aufgerufen.
Umgekehrt behandeln Rückrufe Ereignisse. Wenn das Ereignis, an dem Sie interessiert sind, vor der Registrierung des Rückrufs eingetreten ist, wird der Rückruf nicht aufgerufen.
2. Umkehrung der Kontrolle
Rückrufe beinhalten die Umkehrung der Kontrolle. Wenn Sie eine Rückruffunktion bei einer API registrieren, speichert die Javascript-Laufzeit die Rückruffunktion und ruft sie aus der Ereignisschleife auf, sobald sie zur Ausführung bereit ist.
Eine Erklärung finden Sie in der Javascript-Ereignisschleife .
Bei Promises liegt die Kontrolle beim aufrufenden Programm. Die .then () -Methode kann jederzeit aufgerufen werden, wenn wir das Versprechenobjekt speichern.
quelle
Zusätzlich zu den anderen Antworten fügt sich die ES2015-Syntax nahtlos in Versprechen ein und reduziert noch mehr Code auf dem Boilerplate:
quelle
Versprechen sind keine Rückrufe, beide sind Programmiersprachen, die die asynchrone Programmierung erleichtern. Die Verwendung eines asynchronen / wartenden Programmierstils unter Verwendung von Coroutinen oder Generatoren, die Versprechen zurückgeben, könnte als dritte solche Redewendung angesehen werden. Ein Vergleich dieser Redewendungen in verschiedenen Programmiersprachen (einschließlich Javascript) finden Sie hier: https://github.com/KjellSchubert/promise-future-task
quelle
Nein überhaupt nicht.
Rückrufe sind einfach Funktionen in JavaScript die aufgerufen und nach Abschluss der Ausführung einer anderen Funktion ausgeführt werden sollen. Wie passiert es?
In JavaScript werden Funktionen selbst als Objekte betrachtet, und daher können wie alle anderen Objekte auch Funktionen als Argumente an andere Funktionen gesendet werden . Der häufigste und allgemeinste Anwendungsfall, den man sich vorstellen kann, ist die Funktion setTimeout () in JavaScript.
Versprechen sind nichts anderes als ein viel improvisierterer Ansatz für die Behandlung und Strukturierung von asynchronem Code im Vergleich zu Rückrufen.
Das Versprechen erhält zwei Rückrufe in der Konstruktorfunktion: Auflösen und Ablehnen. Diese Rückrufe innerhalb von Versprechungen bieten uns eine differenzierte Kontrolle über Fehlerbehandlung und Erfolgsfälle. Der Rückruf zum Auflösen wird verwendet, wenn die Ausführung des Versprechens erfolgreich ausgeführt wurde, und der Rückruf zum Ablehnen wird verwendet, um die Fehlerfälle zu behandeln.
quelle
Keine Versprechen sind nur ein Wrapper für Rückrufe
Beispiel Sie können native Javascript-Versprechen mit Knoten js verwenden
quelle
JavaScript-Versprechen verwenden tatsächlich Rückruffunktionen, um zu bestimmen, was zu tun ist, nachdem ein Versprechen aufgelöst oder abgelehnt wurde. Daher unterscheiden sich beide nicht grundlegend. Die Hauptidee hinter Promises besteht darin, Rückrufe entgegenzunehmen - insbesondere verschachtelte Rückrufe, bei denen Sie eine Art von Aktionen ausführen möchten, die jedoch besser lesbar sind.
quelle
Verspricht Übersicht:
In JS können wir asynchrone Operationen (z. B. Datenbankaufrufe, AJAX-Aufrufe) in Versprechen einschließen. Normalerweise möchten wir eine zusätzliche Logik für die abgerufenen Daten ausführen. JS-Versprechen haben Handlerfunktionen, die das Ergebnis der asynchronen Operationen verarbeiten. Die Handlerfunktionen können sogar andere asynchrone Operationen enthalten, die sich auf den Wert der vorherigen asynchronen Operationen stützen können.
Ein Versprechen hat immer die 3 folgenden Zustände:
Ein ausstehendes Versprechen kann gelöst / erfüllt oder mit einem Wert abgelehnt werden. Dann werden die folgenden Handler-Methoden aufgerufen, die Rückrufe als Argumente verwenden:
Promise.prototype.then()
: Wenn das Versprechen aufgelöst ist, wird das Rückrufargument dieser Funktion aufgerufen.Promise.prototype.catch()
: Wenn das Versprechen abgelehnt wird, wird das Rückrufargument dieser Funktion aufgerufen.Obwohl die oben genannten Methoden Rückrufargumente erhalten, sind sie weit überlegen, als nur Rückrufe zu verwenden. Dies ist ein Beispiel, das viel verdeutlicht:
Beispiel
then
Methode aufgerufen und der aufgelöste Wert als Argument für den Rückruf übergebencatch
Methode aufgerufen und der abgelehnte Wert als Argument übergebencatch
undthen
Methoden geben Versprechen zurück, deshalb können wir sie verketten. Sie schließen jeden zurückgegebenen WertPromise.resolve
und jeden ausgelösten Wert (mit demthrow
Schlüsselwort) einPromise.reject
. Jeder zurückgegebene Wert wird also in ein Versprechen umgewandelt, und für dieses Versprechen können wir erneut eine Handlerfunktion aufrufen.catch
Methode alle Fehler, die vor demcatch
Handler aufgetreten sind .quelle