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.
Was ist die Hauptidee?
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:
- Sie müssen die Rückrufe, die den Wert verwenden, nicht kennen, bevor die Aufgabe abgeschlossen ist.
- Anstatt Rückrufe als Argumente für Ihre Funktionen zu erwarten, können Sie ganz einfach
return
ein Promise-Objekt erstellen
- Das Versprechen speichert den Wert und Sie können jederzeit transparent einen Rückruf hinzufügen. Es wird aufgerufen, wenn das Ergebnis verfügbar ist. "Transparenz" bedeutet, dass wenn Sie ein Versprechen haben und einen Rückruf hinzufügen, es für Ihren Code keinen Unterschied macht, ob das Ergebnis bereits eingetroffen ist - die API und die Verträge sind identisch, was das Zwischenspeichern / Auswendiglernen erheblich vereinfacht.
- Sie können problemlos mehrere Rückrufe hinzufügen
Versprechen sind verkettbar ( monadisch , wenn Sie wollen ):
- Wenn Sie den Wert zu transformieren müssen , dass ein Versprechen dar, Sie Karte eine Funktion über das Versprechen verwandeln und ein neues Versprechen zurück, die das transformierte Ergebnis darstellt. Sie können den Wert nicht synchron dazu bringen, ihn irgendwie zu verwenden, aber Sie können die Transformation im Versprechenskontext leicht aufheben . Keine Rückrufe.
- Wenn Sie zwei asynchrone Aufgaben verketten möchten, können Sie die
.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.
var p1 = api1(); // returning a promise
var p3 = p1.then(function(api1Result) {
var p2 = api2(); // returning a promise
return p2; // The result of p2 …
}); // … becomes the result of p3
// So it does not make a difference whether you write
api1().then(function(api1Result) {
return api2().then(console.log)
})
// or the flattened version
api1().then(function(api1Result) {
return api2();
}).then(console.log)
Das Abflachen ist nicht magisch, aber Sie können es leicht tun. Für Ihr stark verschachteltes Beispiel wäre das (nahe) Äquivalent
api1().then(api2).then(api3).then(/* do-work-callback */);
Wenn das Anzeigen des Codes dieser Methoden zum Verständnis beiträgt, finden Sie hier ein paar grundlegende Versprechen in wenigen Zeilen .
Was ist die große Aufregung um Versprechen?
Die Promise-Abstraktion ermöglicht eine viel bessere Zusammensetzbarkeit von Funktionen. Neben der then
Verkettung erstellt die all
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.
Ganz zu schweigen davon, Dinge in Versprechen umwandeln zu müssen.
Bei Bibliotheken mit guten Versprechen ist das eigentlich ziemlich trivial. Siehe Wie konvertiere ich eine vorhandene Rückruf-API in Versprechen?