Ich habe mir das bluebird Versprechen FAQ angesehen, in dem erwähnt wird, dass .then(success, fail)
ein Antipattern ist. Ich verstehe die Erklärung nicht so genau wie das Try and Catch. Was ist daran falsch?
some_promise_call()
.then(function(res) { logger.log(res) }, function(err) { logger.log(err) })
Es scheint, dass das Beispiel das Folgende als den richtigen Weg vorschlägt.
some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })
Was ist der Unterschied?
Was ist der Unterschied?
Der Aufruf .then()
gibt ein Versprechen zurück, das abgelehnt wird, falls der Rückruf einen Fehler auslöst. Das bedeutet, wenn Ihr Erfolg logger
fehlschlägt, wird der Fehler an den folgenden .catch()
-Callback weitergeleitet, jedoch nicht an den fail
-Callback, der mit success
zusammenarbeitet.
Hier ist ein control flow Diagramm:
Um es in synchronem Code auszudrücken:
// some_promise_call().then(logger.log, logger.log)
then: {
try {
var results = some_call();
} catch(e) {
logger.log(e);
break then;
} // else
logger.log(results);
}
Die zweite log
(die dem ersten Argument von .then()
ähnelt) wird nur ausgeführt, wenn keine Ausnahme aufgetreten ist. Der beschriftete Block und die break
-Anweisung fühlen sich ein bisschen seltsam an, genau das hat python try-except-else
für (empfohlenes Lesen!).
// some_promise_call().then(logger.log).catch(logger.log)
try {
var results = some_call();
logger.log(results);
} catch(e) {
logger.log(e);
}
Der catch
-Logger behandelt auch Ausnahmen vom Erfolgsprotokollaufruf.
Soviel zum Unterschied.
Ich verstehe die Erklärung nicht so genau wie das Try and Catch
Das Argument ist, dass Sie normalerweise Fehler in jedem Verarbeitungsschritt abfangen möchten und dass Sie es nicht in Ketten verwenden sollten. Die Erwartung ist, dass Sie nur einen abschließenden Handler haben, der alle Fehler behandelt. Wenn Sie jedoch das "Antipattern" verwenden, werden Fehler in einigen Then-Callbacks nicht behandelt.
Dieses Muster ist jedoch sehr nützlich: Wenn Sie Fehler behandeln möchten, die genau in diesem Schritt aufgetreten sind, und Sie möchten etwas ganz anderes tun, wenn kein Fehler aufgetreten ist, d. H. Wenn der Fehler nicht wiederherstellbar ist. Beachten Sie, dass dies Verzweigung Ihres Kontrollflusses ist. Das ist natürlich manchmal erwünscht.
Was ist daran falsch?
some_promise_call() .then(function(res) { logger.log(res) }, function(err) { logger.log(err) })
Dass Sie Ihren Rückruf wiederholen mussten. Du willst lieber
some_promise_call()
.catch(function(e) {
return e; // it's OK, we'll just log it
})
.done(function(res) {
logger.log(res);
});
Sie könnten auch erwägen, .finally()
dafür zu verwenden.
Die beiden sind nicht ganz identisch. Der Unterschied ist, dass das erste Beispiel keine Ausnahme feststellt, die in Ihrem success
-Handler ausgelöst wird. Wenn Ihre Methode also immer nur gelöste Versprechen zurückgeben soll, wie dies häufig der Fall ist, benötigen Sie einen nachlaufenden catch
-Handler (oder einen anderen then
mit einem leeren success
-Parameter). Sicher, es kann sein, dass Ihr then
-Handler nichts tut, was möglicherweise fehlschlagen könnte. In diesem Fall könnte die Verwendung eines 2-Parameters then
in Ordnung sein.
Ich glaube jedoch, dass der Sinn des Textes, mit dem Sie verlinkt haben, darin besteht, dass then
hauptsächlich Callbacks nützlich ist, um eine Reihe asynchroner Schritte zu verketten und wenn Sie dies tatsächlich tun, die 2-Parameter-Form von then
verhält sich aus dem oben genannten Grund nicht ganz so, wie erwartet. Es ist besonders nicht intuitiv, wenn es in der Mitte der Kette verwendet wird.
Als jemand, der viel komplizierte asynchrone Sachen gemacht hat und in Ecken wie diese gestoßen ist, mehr als ich zugeben möchte, empfehle ich wirklich, dieses Anti-Pattern zu vermeiden und auf den separaten Handler-Ansatz zu gehen.
Indem wir die Vor- und Nachteile beider betrachten, können wir eine kalkulierte Abschätzung machen, welche der Situation angemessen ist. Dies sind die zwei Hauptansätze zur Umsetzung von Versprechen. Beide haben Plus und Minus
Fangansatz
some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })
Vorteile
Nachteile
Erfolg/Fehleransatz
some_promise_call()
.then(function success(res) { logger.log(res) },
function error(err) { logger.log(err) })
Vorteile
Nachteile
catch
, wenn Sie Fehler behandeln möchten, die vom Erfolgsrückruf ausgelöst werdenEinfach erklären:
In ES2018
Wenn die catch-Methode mit dem Argument onRejected aufgerufen wird, wird die Folgende Schritte werden unternommen:
- Versprechen sei dieser Wert.
- Rückkehr ? Invoke (Versprechen, "dann", "undefined, onRejected").
das bedeutet:
promise.then(f1).catch(f2)
gleich
promise.then(f1).then(undefiend, f2)
Mit .then().catch()
können Sie Promise Chaining aktivieren, das zur Erfüllung eines Workflows erforderlich ist. Möglicherweise müssen Sie einige Informationen aus der Datenbank lesen, um sie an eine asynchrone API zu übergeben und anschließend die Antwort zu bearbeiten. Möglicherweise möchten Sie die Antwort zurück in die Datenbank übertragen. Die Handhabung all dieser Workflows mit Ihrem Konzept ist machbar, aber sehr schwierig zu verwalten. Die bessere Lösung ist then().then().then().then().catch()
, die alle Fehler in nur einem Fang erhält und Sie die Wartbarkeit des Codes behalten lässt.