Wann gilt .then(Erfolg, Misserfolg) als Antimuster für Versprechungen?

Lesezeit: 9 Minuten

Wann gilt thenErfolg Misserfolg als Antimuster fur Versprechungen
Benutzer2127480

Ich habe mir die angeschaut Häufig gestellte Fragen zum Bluebird-Versprechenin dem das erwähnt wird .then(success, fail) ist ein Antimuster. Ich verstehe die Erklärung für die nicht ganz try und catch. Was ist an folgendem 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?

  • then().catch() ist besser lesbar, da Sie nicht nach dem Komma suchen und diesen Callback für den erfolgreichen oder fehlgeschlagenen Zweig untersuchen müssen.

    – Krzysztof Safjanowski

    9. Juli 2014 um 20:04 Uhr

  • @KrzysztofSafjanowski – am Boden zerstört von dem Argument “sieht besser aus”. Total falsch!

    – Andrej Popov

    27. Februar 2015 um 14:23 Uhr

  • @AndreyPopov wo siehst du „sieht besser aus“?. Bitte lesen Sie die nächste Antwort und was besser lesbar ist .then(function(res) { logger.log(res) }, function(err) { logger.log(err) }) oder .then(function(res) { logger.log(res) }).catch( function(err) { logger.log(err) })

    – Krzysztof Safjanowski

    28. Februar 2015 um 17:59 Uhr

  • HINWEIS: Wenn Sie verwenden .catchwissen Sie nicht, welcher Schritt das Problem verursacht hat – innerhalb des letzten then oder irgendwo anders in der Versprechenskette. Es hat also seinen eigenen Nachteil.

    – vitaly-t

    25. Oktober 2015 um 13:07 Uhr


  • Ich füge den Promise .then() -Parametern immer Funktionsnamen hinzu, um sie lesbar zu machen, dh some_promise_call() .then(function fulfilled(res) { logger.log(res) }, function rejected(err) { logger.log(err) })

    – Shane Rowatt

    7. Juli 2016 um 0:07 Uhr

1646806512 805 Wann gilt thenErfolg Misserfolg als Antimuster fur Versprechungen
Bergi

Was ist der Unterschied?

Die .then() call gibt ein Promise zurück, das abgelehnt wird, falls der Callback einen Fehler auslöst. Das bedeutet, wenn Ihr Erfolg logger fehlschlägt, wird der Fehler an Folgendes weitergegeben .catch() Rückruf, aber nicht an die fail Rückruf, der daneben geht success.

Hier ist ein Kontrollfluss Diagramm:

Kontrollflussdiagramm von then mit zwei Argumenten
Steuerflussdiagramm der Fangkette

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);
}

Der Zweite log (was wie das erste Argument zu ist .then()) wird nur ausgeführt, wenn keine Ausnahme aufgetreten ist. Der beschriftete Block und die break Anweisung fühlt sich etwas seltsam an, das ist eigentlich das, was Python hat try-except-else für (Leseempfehlung!).

// some_promise_call().then(logger.log).catch(logger.log)
try {
    var results = some_call();
    logger.log(results);
} catch(e) {
    logger.log(e);
}

Die catch logger behandelt auch Ausnahmen vom erfolgreichen Logger-Aufruf.

So viel zum Unterschied.

Ich verstehe die Erklärung für das Try and Catch nicht ganz

Das Argument ist, dass Sie normalerweise Fehler in jedem Schritt der Verarbeitung abfangen möchten und dass Sie es nicht in Ketten verwenden sollten. Die Erwartung ist, dass Sie nur einen letzten Handler haben, der alle Fehler behandelt – während bei Verwendung des “Antimusters” Fehler in einigen der Then-Callbacks nicht behandelt werden.

Dieses Muster ist jedoch sehr nützlich: Wenn Sie Fehler behandeln möchten, die in genau diesem Schritt aufgetreten sind, und etwas tun möchten ganz anders wenn kein Fehler aufgetreten ist – dh wenn der Fehler nicht behebbar ist. Sei vorsichtig dass das ist Verzweigung Ihr Kontrollfluss. Natürlich ist dies manchmal erwünscht.


Was ist an folgendem 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 die Verwendung von in Betracht ziehen .finally() dafür.

  • Dies ist das hilfreichste Erklärung Ich habe in ein paar Tagen gelesen (und ich habe viel gelesen). Ich kann nicht erklären, wie dankbar ich bin! 🙂 Ich denke, Sie sollten den Unterschied zwischen den beiden mehr betonen, das .catch Wille Fehler auch innerhalb der Erfolgsfunktion abfangen.. Ich persönlich finde das extrem falsch, da Sie mit einem Fehlereintrittspunkt enden, der mehrere Fehler aus mehreren Aktionen erhalten kann, aber das ist mein Problem. Wie auch immer – danke für die Info! Hast du kein Online-Kommunikationstool, das du bereit bist zu teilen, damit ich noch ein paar Dinge fragen kann? 😛

    – Andrej Popow

    27. Februar 2015 um 14:21 Uhr

  • Ich hoffe, das gibt Ihnen hier noch mehr Upvotes. Definitiv eine der besten Erklärungen für ein wichtiges Promise Mechaniker auf dieser Seite.

    – Patrick Roberts

    2. Februar 2018 um 21:28 Uhr

  • .done() gehört nicht zum Standard, oder? Zumindest listet MDN diese Methode nicht auf. Es wäre hilfreich.

    – ja

    31. März 2019 um 17:52 Uhr

  • @ygoe In der Tat. done ist eine Bluebird-Sache, die im Grunde von abgelehnt wurde then+Unhandled-Rejection-Erkennung.

    – Bergi

    31. März 2019 um 18:58 Uhr

  • Nur eine Anmerkung von einem Farbenblinden: Die Diagramme machen keinen Sinn 🙂

    – Benni K

    22. November 2019 um 7:28 Uhr

Wann gilt thenErfolg Misserfolg als Antimuster fur Versprechungen
acjay

Die beiden sind nicht ganz identisch. Der Unterschied besteht darin, dass das erste Beispiel keine Ausnahme abfängt, die in Ihrem ausgelöst wird success Handler. Wenn Ihre Methode also immer nur aufgelöste Promises zurückgeben soll, wie es oft der Fall ist, benötigen Sie ein Trailing catch Handler (oder noch ein anderer then mit einem leeren success Parameter). Sicher, es kann sein, dass Ihre then Der Handler tut nichts, was möglicherweise fehlschlagen könnte, in diesem Fall wird ein 2-Parameter verwendet then könnte gut sein.

Aber ich glaube, der Punkt des Textes, auf den Sie verlinkt haben, ist das then ist im Vergleich zu Rückrufen am nützlichsten, da es möglich ist, eine Reihe asynchroner Schritte zu verketten, und wenn Sie dies tatsächlich tun, die 2-Parameter-Form von then subtil verhält sich aus dem oben genannten Grund nicht ganz wie erwartet. Es ist besonders kontraintuitiv, wenn es in der Mitte der Kette verwendet wird.

Als jemand, der viel komplexes asynchrones Zeug gemacht hat und öfter auf solche Ecken gestoßen ist, als ich zugeben möchte, empfehle ich wirklich, dieses Anti-Pattern zu vermeiden und den separaten Handler-Ansatz zu wählen.

1646806514 687 Wann gilt thenErfolg Misserfolg als Antimuster fur Versprechungen
aWebDeveloper

Indem wir die Vor- und Nachteile beider betrachten, können wir eine kalkulierte Vermutung anstellen, welche für die Situation angemessen ist. Dies sind die beiden Hauptansätze zur Umsetzung von Versprechen. Beides hat seine Vor- und Nachteile

Fangansatz

some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })

Vorteile

  1. Alle Fehler werden von einem Catch-Block behandelt.
  2. Fängt sogar jede Ausnahme im then-Block ab.
  3. Verkettung mehrerer Erfolgsrückrufe

Nachteile

  1. Bei Verkettung wird es schwierig, unterschiedliche Fehlermeldungen anzuzeigen.

Erfolgs-/Fehleransatz

some_promise_call()
.then(function success(res) { logger.log(res) },
      function error(err) { logger.log(err) })

Vorteile

  1. Sie erhalten eine feinkörnige Fehlerkontrolle.
  2. Sie können eine gemeinsame Fehlerbehandlungsfunktion für verschiedene Fehlerkategorien wie DB-Fehler, 500-Fehler usw. haben.

Nachteile

  1. Sie werden noch eine andere brauchen catch wenn Sie Fehler behandeln möchten, die vom Erfolgs-Callback ausgelöst werden

  • Für jemanden, der Produktionsprobleme nur mit einer Protokolldatei debuggen muss, bevorzuge ich den Erfolgs-/Fehleransatz, da er die Möglichkeit bietet, eine kausale Fehlerkette zu erstellen, die an den Exit-Grenzen Ihrer App protokolliert werden kann.

    – Shane Rowatt

    7. Juli 2016 um 0:03 Uhr

  • Frage. Nehmen wir an, ich mache einen asynchronen Aufruf, der eines der folgenden Dinge tut: 1) erfolgreich zurückgegeben (2xx Statuscode), 2) erfolglos zurückgegeben (4xx- oder 5xx-Code), aber nicht per se abgelehnt, 3) oder überhaupt nicht zurückgegeben ( Internetverbindung ist unterbrochen). Für Fall Nr. 1 wird der Erfolgs-Callback in .then getroffen. Für Fall Nr. 2 wird der Fehler-Callback in .then getroffen. Für Fall Nr. 3 wird .catch aufgerufen. Das ist eine korrekte Analyse, oder? Fall Nr. 2 ist am kniffligsten, da technisch gesehen ein 4xx oder 5xx keine Ablehnung ist, es wird trotzdem erfolgreich zurückgegeben. Daher müssen wir es innerhalb von .then handhaben. ….Ist mein Verständnis richtig?

    – Benjamin Hoffmann

    30. August 2017 um 14:47 Uhr


  • “Für Fall Nr. 2 wird der Fehler-Callback in .then getroffen. Für Fall Nr. 3 wird .catch aufgerufen. Dies ist eine korrekte Analyse, oder?” – So funktioniert Holen

    – ein Webentwickler

    3. September 2017 um 16:07 Uhr

1646806514 119 Wann gilt thenErfolg Misserfolg als Antimuster fur Versprechungen
Bytefisch

Einfach erklären:

Im ES2018

Wenn die catch-Methode mit dem Argument onRejected aufgerufen wird, werden die folgenden Schritte ausgeführt:

  1. Lassen Sie das Versprechen der this-Wert sein.
  2. Zurückkehren ? Invoke(promise, “then”, « undefined, onRejected »).

das bedeutet:

promise.then(f1).catch(f2)

gleich

promise.then(f1).then(undefiend, f2)

Verwenden .then().catch() können Sie aktivieren Versprechen Verkettung die zur Erfüllung eines Workflows benötigt wird. Möglicherweise müssen Sie einige Informationen aus der Datenbank lesen, dann möchten Sie sie an eine asynchrone API übergeben und dann die Antwort 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 schwer zu verwalten. Die bessere Lösung wird sein then().then().then().then().catch() der alle Fehler auf einmal auffängt und Sie behalten lässt Wartbarkeit des Codes.

Verwenden then() und catch() hilft Kettenerfolg und Misserfolg Handler auf das Versprechen.catch() funktioniert auf Versprechen zurückgegeben von then(). Es handhabt,

  1. Wenn das Versprechen abgelehnt wurde. Siehe Nr. 3 im Bild
  2. Wenn im Erfolgshandler von then() ein Fehler aufgetreten ist, zwischen den Zeilennummern 4 bis 7 unten. Siehe #2.a im Bild (Failure callback on then() verarbeitet das nicht.)
  3. Wenn ein Fehler in der Fehlerbehandlung von then() aufgetreten ist, Zeile Nummer 8 unten. Siehe #3.b im Bild.


1. let promiseRef: Promise = this. aTimetakingTask (false);
2. promiseRef
3. .then(
4. (result) => {
5. /* successfully, resolved promise.
6. Work on data here */
7. },
8. (error) => console.log(error)
9. )
10. .catch( (e) => {
11. /* successfully, resolved promise.
12. Work on data here */
13. });

Geben Sie hier die Bildbeschreibung ein

Notiz: Häufig ist der Fehlerbehandler möglicherweise nicht definiert, wenn catch() ist schon geschrieben. BEARBEITEN: reject() zum Aufruf führen catch() nur wenn der errorhandler in then() ist nicht definiert. Beachten Sie # 3 im Bild zum catch(). Es wird aufgerufen, wenn Handler in Zeile 8 und 9 nicht definiert sind.

Es macht Sinn, weil das Versprechen zurückgegeben wird then() hat keinen Fehler, wenn ein Callback sich darum kümmert.

Statt Worte, gutes Beispiel. Folgender Code (wenn erstes Versprechen gelöst):

Promise.resolve()
.then
(
  () => { throw new Error('Error occurs'); },
  err => console.log('This error is caught:', err)
);

ist identisch mit:

Promise.resolve()
.catch
(
  err => console.log('This error is caught:', err)
)
.then
(
  () => { throw new Error('Error occurs'); }
)

Aber mit abgelehntem ersten Versprechen ist dies nicht identisch:

Promise.reject()
.then
(
  () => { throw new Error('Error occurs'); },
  err => console.log('This error is caught:', err)
);

Promise.reject()
.catch
(
  err => console.log('This error is caught:', err)
)
.then
(
  () => { throw new Error('Error occurs'); }
)

  • Das ergibt keinen Sinn. Können Sie diese Antwort bitte entfernen? Es ist irreführend und lenkt von der richtigen Antwort ab.

    – Andy Ray

    15. Mai 2018 um 4:00 Uhr

  • @AndyRay, das macht in der realen Anwendung keinen Sinn, aber es ist sinnvoll, die Arbeit der Versprechen zu verstehen.

    – ktretjak

    15. Mai 2018 um 8:12 Uhr

  • Ich denke, dieser Code braucht einige Worte, damit wir verstehen können, was er uns sagen will. Wie sind sie identisch und wie sind sie nicht identisch?

    – Juan Mendes

    27. Juli 2021 um 15:05 Uhr

980860cookie-checkWann gilt .then(Erfolg, Misserfolg) als Antimuster für Versprechungen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy