web-dev-qa-db-de.com

Was ist der Unterschied zwischen damals und schließlich in einem Versprechen?

Ich sehe die Dokumentation zu Bluebirds finally , verstehe den Unterschied zu then aber immer noch nicht ganz.

Um es klar auszudrücken: Ich weiß genau, warum then nach einer catch aufgerufen wird. Ich will es soll nach einem Fang aufgerufen werden. Das ist die Absicht. Meine Frage lautet: Wenn I want code unabhängig vom Versprechungsstatus immer ausgeführt werden soll, worin besteht der Unterschied zwischen then und finally?

Ich habe diesen Test gebaut:

var Promise = require("bluebird");

function test1 () {
    console.log("RESOLVE + THEN + CATCH + THEN");
    return new Promise((resolve, reject) => resolve())
       .then(() => console.log("then"))
       .catch(err => console.log("error:", err.message))
       .then(() => console.log("end"));
}

function test2 () {
    console.log("REJECT + THEN + CATCH + THEN");
    return new Promise((resolve, reject) => reject(new Error("rejected")))
       .then(() => console.log("then"))
       .catch(err => console.log("error:", err.message))
       .then(() => console.log("end"));
}

function test3 () {
    console.log("RESOLVE + THEN + CATCH + FINALLY");
    return new Promise((resolve, reject) => resolve())
       .then(() => console.log("then"))
       .catch(err => console.log("error:", err.message))
       .finally(() => console.log("end"));
}

function test4 () {
    console.log("REJECT + THEN + CATCH + FINALLY");
    return new Promise((resolve, reject) => reject(new Error("rejected")))
       .then(() => console.log("then"))
       .catch(err => console.log("error:", err.message))
       .finally(() => console.log("end"));
}

// run tests "sequentially" so console output doesn't get blended
setTimeout(test1, 500);
setTimeout(test2, 1000);
setTimeout(test3, 1500);
setTimeout(test4, 2000);

Dies testet vier Fälle:

  1. .then(...).catch(...).then(...) mit einem entschlossenen Versprechen.
  2. .then(...).catch(...).then(...) mit einem abgelehnten Versprechen.
  3. .then(...).catch(...).finally(...) mit einem entschlossenen Versprechen.
  4. .then(...).catch(...).finally(...) mit einem abgelehnten Versprechen.

Die Ergebnisse, die ich sehe, sind Fälle 1 + 2, die sich identisch zu 3 + 4 verhalten: Das letzte Bit (then oder finally, je nach Test) wird ausgeführt, unabhängig davon, was vor ihm passiert, wie beabsichtigt. Die Ausgabe dieses Programms ist:

RESOLVE + THEN + CATCH + THEN
then
end
REJECT + THEN + CATCH + THEN
error: rejected
end
RESOLVE + THEN + CATCH + FINALLY
then
end
REJECT + THEN + CATCH + FINALLY
error: rejected
end

Der Grund, warum ich frage, ist, dass ich einen Kommentar zu dieser anderen Frage gesehen habe, die ich gestellt habe :

Nicht sicher, ob Ihre Versprechen dies unterstützen, aber Sie sollten den letzten .then in .finally ändern, damit die busy immer gelöscht wird.

Aufgrund meiner sehr begrenzten Kenntnisse über then und der obigen Tests scheint then ausreichend zu sein. Aber nach diesem Kommentar frage ich mich und die Sicherheit der Verwendung von then, um "finally" -Code auszuführen.

Meine Frage lautet also: Was ist der Unterschied zwischen then und finally? Sie sehen so aus, als ob sie sich gleich verhalten, aber wann müsste ich finally anstelle von then verwenden?

4
Jason C

Erster Unterschied: Manchmal möchten Sie keine Fehler an der Stelle abfangen, an der sie auftreten, sondern im Code, der diese Funktion verwendet, damit Sie sie nicht abfangen. In diesem Fall können Sie then() und finally() nicht ersetzen. 

Manchmal müssen Sie etwas aufräumen, ob ein Fehler aufgetreten ist oder nicht (Verweise auf Null setzen, Zeitüberschreitungen löschen usw.). Dort verwenden Sie finally()

Zweiter Unterschied: Die Funktion, die Sie an catch() übergeben, könnte auch werfen, dann hätten Sie ein abgelehntes Promise und die folgende then() würde nicht aufgerufen.

(also ein final bevor ein catch wird noch auf einen fehler ausgeführt, wußte das nicht)

Ja, das ist der Punkt von finally(). Es wird unter allen Umständen ausgeführt, ohne den aufgelösten Wert zu ändern.

Vielleicht möchten Sie etwas über try {} finally {} lesen/googleen, ohne zu fangen.

7
Thomas

.then und .finally stimmen nicht überein.

.then ist das Hauptversprechen. Es ist genau das, was in der Promises/A + spec definiert ist, und alle Versprechenbibliotheken werden es implementieren.

Ein Bluebird .finally - Handler wird "unabhängig vom Schicksal des Versprechens" aufgerufen. Eine unbehandelte Ausnahme löst also immer noch einen .finally aus.

new Promise((resolve, reject) => reject(false))
  .finally(a => console.log('finally', a))
// finally undefined
// Unhandled rejection false

new Promise((resolve, reject) => reject(false))
  .then(a => console.log('then', a))
// Unhandled rejection false

.finally ändert den aufgelösten Wert des Versprechens nicht und erhält das Ergebnis der Versprechenkette nicht. 

new Promise((resolve, reject) => reject(false))
  .catch(e => {
    console.log(e)
    return 2
  })
  .finally(a => {
    console.log('finally', a)
    return 1
  })
  .then(res => console.log('res', res))
// finally undefined
// res 2

Die Methoden sehen in Ihren Testfällen ähnlich aus, da die Tests alle Fehler abfangen und Sie nur Versprechungen für die Flusskontrolle verwenden und sich nicht auf die Auflösung/Ablehnung der Werte entlang der Versprechenkette verlassen.

3
Matt

In Ordnung, nach ein paar Gesprächen und viel Hilfe von KevinB habe ich wenigstens einen Unterschied herausgefunden. Betrachten Sie die folgenden zwei neuen Tests:

function test5 () {
    console.log("REJECT + THEN + CATCH/THROW + THEN");
    return new Promise((resolve, reject) => reject(new Error("rejected")))
       .then(() => console.log("then"))
       .catch(function(err) { throw new Error("error in catch"); })
       .then(() => console.log("end"));
}

function test6 () {
    console.log("REJECT + THEN + CATCH/THROW + FINALLY");
    return new Promise((resolve, reject) => reject(new Error("rejected")))
       .then(() => console.log("then"))
       .catch(function(err) { throw new Error("error in catch"); })
       .finally(() => console.log("end"));
}

In diesen wird das Versprechen abgelehnt, aber es wird ein Fehler von catch ausgegeben.

Das Versprechen wird letztendlich in beiden Fällen abgelehnt, aber für den Fall finally wird die finally noch ausgeführt, die then nicht.

Also das ist der Unterschied. Sie sind fast - mit der einzigen Ausnahme, dass, wenn ein Fehler vomcatch-Handler ausgegeben wird, finally ausgeführt wird und then dies nicht tut.

Das bedeutet, dass der Kommentar, den ich zitiert habe, auch Vorzüge hat: Wenn in meinem Fehlerbehandlungsprogramm ein anderer Fehler aufgetreten ist, würde eine then keine Bereinigung garantieren, eine finally jedoch. Das ist der Fall, den ich vermisst habe.

1
Jason C