Ich habe älteren Node.js-Code, den ich aktualisiere. Dabei entwerfe ich neue Module, um mit dem alten Code zu arbeiten. Ich stelle fest, dass ich mich im Gegensatz zum ersten Schreiben mehr auf die Verwendung von ES6-Versprechungen als auf Rückrufe stütze. Nun habe ich diese Mischung aus einigen Funktionen, die Versprechen zurückgeben und einige Rückrufe annehmen - was mühsam ist. Ich denke, es sollte überarbeitet werden, um Versprechungen zu verwenden. Aber bevor das erledigt ist ...
In welchen Situationen werden Versprechen bevorzugt und wo werden Rückrufe bevorzugt?
Gibt es eine Situation, die ein Rückruf besser bewältigen kann als ein Versprechen und umgekehrt?
Basierend auf dem, was ich bisher gesehen habe, sehe ich keinen Grund, Callbacks anstelle von Versprechen zu verwenden. Ist das wahr?
Zunächst einmal möchten Sie eigentlich nie Code schreiben, der eine Mischung aus Rückrufen und Versprechen für asynchrone Operationen ist. Wenn Sie zu Versprechungen wechseln oder einige Versprechen einführen, möchten Sie wahrscheinlich die Rückrufe in demselben Abschnitt des Codes in Versprechen umwandeln. Für die entsprechenden Arten von Operationen gibt es so viele Vorteile, dass Versprechungen im Vergleich zu einfachen Rückrufen so viele Vorteile bieten, dass sich die Konvertierung lohnt, wenn bereits in einem Code-Bereich gearbeitet wird.
Versprechen sind großartig für:
pending
, fulfilled
und rejected
und bei denen der Statusübergang von pending => fulfilled
oder von pending => rejected
nicht geändert werden kann (ein einzelner Einwegübergang).Einfache Rückrufe sind für Dinge gut, die Versprechen nicht können:
Array.prototype.map()
)Und ich würde auch EventEmitter
zum Mix hinzufügen.
EventEmitters eignen sich hervorragend für:
Hinweise zum Konvertieren eines einfachen Rückrufcodes in Promises
Wenn Ihre Rückrufe in die Knotenaufrufkonvention passen, wobei der Rückruf als letztes Argument übergeben und wie callback(err, result)
aufgerufen wird, wickeln Sie die übergeordnete Funktion mit util.promisify()
in node.js oder mit der Bluebird Promise-Bibliothek mit Promise.promisify()
.
Mit Bluebird können Sie sogar ein gesamtes Modul (das async-Callbacks in der node.js-Aufrufkonvention verwendet) auf einmal aktivieren, z.
const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs'));
fs.writeFileAsync("file.txt", data).then(() => {
// done here
}).catch(err => {
// error here
});
In node.js Version 8+
Es gibt jetzt util.promisify()
, das eine async-Funktion, die die async-Aufrufkonvention von node.js verwendet, in eine Funktion konvertiert, die ein Versprechen zurückgibt.
Beispiel aus das Dokument:
const util = require('util');
const fs = require('fs');
const stat = util.promisify(fs.stat);
// usage of promisified function
stat('.').then((stats) => {
// Do something with `stats`
}).catch((error) => {
// Handle the error.
});
Sie existieren beide, um das gleiche Problem zu lösen, und behandeln das Ergebnis einer asynchronen Funktion.
Callbacks sind in der Regel ausführlicher und das gleichzeitige Koordinieren mehrerer asynchroner Anforderungen kann zu callback hell führen, wenn Sie Ihre Funktionen nicht aktiv modularisieren. Fehlerbehandlung und -verfolgung sind in der Regel weniger unkompliziert und sogar verwirrend, da es viele Fehlerobjekte geben kann, die alle auf einen einzelnen Fehler zurückgehen, der sich im Aufrufstapel befindet. Fehler müssen auch an den ursprünglichen Aufrufer zurückgegeben werden. Dies kann auch zu Kopfschmerzen führen, wenn festgestellt wird, wo der ursprüngliche Fehler ausgegeben wurde, wenn anonyme Funktionen in der Rückrufkette verwendet wurden. Callbacks haben den Vorteil, dass es sich bei ihnen lediglich um alte Funktionen handelt, die kein weiteres Verständnis erfordern, wenn man nicht weiß, wie ein asynchroner Vorgang funktioniert.
Versprechungen sind häufiger, da sie weniger Code erfordern, lesbarer sind, da sie wie synchrone Funktionen geschrieben werden, einen einzigen Fehlerkanal haben, ausgelöste Fehler behandeln können und util.promisify()
in der neuesten Version von Node.js hinzugefügt wird , kann Error-First Callbacks in Versprechen umwandeln. Es gibt auch async/await
, das jetzt auch in Node.js ist, und sie sind auch mit Promises verbunden.
Dies ist absolut auf der Meinung nach basiert, also geht es wirklich darum, was Sie am besten können, aber Promises und async/await
sind die Entwicklung des Rückrufs und verbessern die asynchrone Entwicklung. Dies ist keinesfalls ein erschöpfender Vergleich, sondern ein Blick auf Callbacks und Versprechen auf hoher Ebene.
Ich weiß nicht mehr, woher ich dieses Zeug bekommen habe, aber es könnte hilfreich sein, Versprechen besser zu verstehen.
Versprechen sind keine Rückrufe. Ein Versprechen stellt das zukünftige Ergebnis einer asynchronen Operation dar. Wenn Sie sie so schreiben, wie Sie es tun, haben Sie wenig Nutzen. Wenn Sie sie jedoch so schreiben, wie sie verwendet werden sollen, können Sie asynchronen Code auf eine Weise schreiben, die synchronem Code ähnelt und viel einfacher zu folgen ist: VORTEILE 1. Lesbarkeit über Rückrufe 2. Fehler leicht zu fangen .. 3. Gleichzeitige Rückrufe
1. Lesbarkeit über Rückrufe Versprechungen bieten eine prägnantere und klarere Darstellung von sequentiellen asynchronen Vorgängen in Javascript. Sie sind praktisch eine andere Syntax, um denselben Effekt wie Callbacks zu erzielen. Der Vorteil ist eine erhöhte Lesbarkeit. Etwas wie das
aAsync()
.then(bAsync)
.then(cAsync)
.done(finish);
ist viel lesbarer als das Äquivalent der Übergabe jeder dieser einzelnen Funktionen als Rückrufe, wie
Async(function(){ return bAsync(function(){ return cAsync(function(){ finish() }) }) });
//-------------------------------------------- api().then(function(result){
return api2(); }).then(function(result2){ return api3(); }).then(function(result3){ // do work });
2. Einfach, Fehler zu fangen. Sicher nicht viel weniger Code, aber viel lesbarer. Dies ist jedoch nicht das Ende. Entdecken Sie die wahren Vorteile: Was wäre, wenn Sie in einem der Schritte nach Fehlern suchen wollten? Es wäre die Hölle, es mit Rückrufen zu tun, aber mit Versprechen ist es ein Kinderspiel:
api().then(function(result){
return api2(); }).then(function(result2){ return api3(); }).then(function(result3){ // do work }).catch(function(error) {
//handle any error that may occur before this point });
/* Pretty much the same as a try { ... } catch block.
Even better: */
api().then(function(result){ return api2(); }).then(function(result2){ return api3(); }).then(function(result3){ // do work }).catch(function(error) { //handle any error that may occur before this point }).then(function() { //do something whether there was an error or not //like hiding an spinner if you were performing an AJAX request. });
3. Gleichzeitige Rückrufe Und noch besser: Was wäre, wenn diese 3 Aufrufe an api, api2, api3 gleichzeitig ablaufen könnten (z. B. wenn es sich um Aufrufe von AJAX handelt), aber Sie mussten auf die drei warten? Ohne Versprechen sollten Sie eine Art Zähler erstellen. Mit den Versprechen, die ES6-Notation zu verwenden, ist ein weiteres Stück Kuchen und ziemlich ordentlich:
Promise.all([api(), api2(), api3()]).then(function(result) { //do work. result is an array contains the values of the three fulfilled promises. }).catch(function(error) { //handle the error. At least one of the promises rejected. });
Ich hoffe, Sie sehen jetzt Versprechen in einem neuen Licht.