Fehler beim Versprechen erneut werfen

83

Ich habe den folgenden Code in einem Tutorial gefunden:

promise.then(function(result){
    //some code
}).catch(function(error) {
    throw(error);
});

Ich bin ein bisschen verwirrt: Erreicht der Catch Call etwas? Es scheint mir, dass es keine Wirkung hat, da es einfach den gleichen Fehler auslöst, der abgefangen wurde. Ich stütze mich darauf, wie ein regelmäßiger Versuch / Fang funktioniert.

Tyler Durden
quelle
Könnten Sie einen Link zum Tutorial bereitstellen? Vielleicht gibt es zusätzlichen Kontext, der hilfreich wäre ...
Igor
@Igor Ich kann nicht, es ist auf Pluralsight. Ist dies möglicherweise nur ein Platzhalter für eine Fehlerübergabelogik?
Tyler Durden
Das würde ich vermuten, da es nichts weiter tut, als den Fehler an den Anrufer weiterzuleiten, was auch dadurch erreicht werden könnte, dass der Fang zunächst nicht vorhanden ist.
Igor
1
@ TylerDurden Ich vermute, dass Sie Recht haben, wenn es sich um einen Platzhalter handelt.
Jared Smith
@ TylerDurden, ich würde auch vermuten, dass es ein Platzhalter ist. Vielleicht versuchen Sie zu demonstrieren, wie Fehler formatiert / normalisiert werden. Grundsätzlich das Versprechen-Äquivalent zu try { ... }catch(error){ throw new Error("something went wrong") }. Oder um zu zeigen, dass Versprechen und Fehler kompatibel sind (zumindest so) . Aber in seiner aktuellen Implementierung ist es einfach nur dumm. Sie haben Recht, es macht nichts und es ist nicht einmal wie ein Hook, den Sie in OOP hinzufügen würden, um das Überschreiben in einer ererbenden Klasse zu ermöglichen. Ich würde den catch-Block hinzufügen, sobald er etwas tut, aber nicht so, nicht nur als Platzhalter.
Thomas

Antworten:

118

Es hat keinen Sinn, nackt zu fangen und zu werfen, wie Sie zeigen. Es macht nichts Nützliches außer dem Hinzufügen von Code und der langsamen Ausführung. Wenn Sie also gehen .catch()und erneut werfen, sollte es etwas geben, das Sie in der tun möchten .catch(), andernfalls sollten Sie das einfach .catch()vollständig entfernen .

Der übliche Punkt für diese allgemeine Struktur ist, wenn Sie etwas ausführen möchten, .catch()z. B. den Fehler protokollieren oder einen Status bereinigen möchten ( z. B. Dateien schließen), die Versprechen-Kette jedoch als abgelehnt fortgesetzt werden soll.

promise.then(function(result){
    //some code
}).catch(function(error) {
    // log and rethrow 
    console.log(error);
    throw error;
});

In einem Tutorial kann es nur dazu dienen, Personen zu zeigen, wo sie Fehler abfangen können, oder das Konzept des Umgangs mit dem Fehler zu lehren und ihn dann erneut zu werfen.


Einige der nützlichen Gründe für das Fangen und Umwerfen sind folgende:

  1. Sie möchten den Fehler protokollieren , aber die Versprechen-Kette als abgelehnt beibehalten.
  2. Sie möchten den Fehler in einen anderen Fehler umwandeln (häufig zur einfacheren Fehlerverarbeitung am Ende der Kette). In diesem Fall würden Sie einen anderen Fehler erneut auslösen.
  3. Sie möchten eine Reihe von Verarbeitungen durchführen, bevor die Versprechen-Kette fortgesetzt wird (z. B. enge / freie Ressourcen), aber Sie möchten, dass die Versprechen-Kette abgelehnt bleibt.
  4. Sie möchten, dass ein Punkt an dieser Stelle in der Versprechen-Kette einen Haltepunkt für den Debugger setzt , wenn ein Fehler auftritt.

Ein einfaches Abfangen und erneutes Auslösen desselben Fehlers ohne anderen Code im catch-Handler ist jedoch für die normale Ausführung des Codes nicht hilfreich.

jfriend00
quelle
Meiner Meinung nach ist es kein gutes Beispiel. Mit einem solchen Ansatz erhalten Sie einfach mehrere Protokolle für 1 Fehler. In Java kann man einfach throw new Exception(periousException);nicht wissen, ob Javascript verschachtelte Fehler unterstützt, aber trotzdem ist "log and throw" eine schlechte Praxis.
Cherry
25
@Cherry - Man kann nicht sagen, dass dies im Allgemeinen eine schlechte Praxis ist. Es gibt Zeiten, in denen ein Modul seine eigenen Fehler auf seine eigene Weise protokollieren möchte, und dies ist eine Möglichkeit, dies zu tun. Außerdem empfehle ich dies nicht, ich erkläre nur, dass es keinen Grund gibt, einen .catch()Fehler in den Haken zu werfen, es sei denn, Sie tun etwas anderes in der .catch(). Darum geht es bei dieser Antwort.
jfriend00
Im Allgemeinen sollten Ausnahmen zur Abstraktionsebene passen. Es ist vollkommen in Ordnung, beispielsweise eine db-bezogene Ausnahme abzufangen und so etwas wie eine "Service" -Ausnahme auszulösen, die vom Anrufer behandelt wird. Dies ist besonders nützlich, wenn Sie keine Details zu Ausnahmen auf niedriger Ebene
offenlegen möchten
3
Ein weiterer guter Grund zum Fangen und (manchmal) Werfen ist, einen bestimmten Fehler zu behandeln, aber alles andere neu zu werfen.
Jasper
2
@SimonZyx - Ja, .finally()kann dafür sehr nützlich sein, aber manchmal werden die Ressourcen bereits im fehlerfreien Pfad gepflegt, sodass Sie sie .catch()immer noch schließen können. Es kommt wirklich auf die Situation an.
jfriend00
14

Beide .then()und .catch()Methoden geben Versprechen zurück. Wenn Sie in einem der beiden Handler eine Ausnahme auslösen, wird das zurückgegebene Versprechen abgelehnt und die Ausnahme wird im nächsten Ablehnungshandler abgefangen.

Im folgenden Code lösen wir im ersten eine Ausnahme aus .catch(), die im zweiten abgefangen wird .catch():

new Promise((resolve, reject) => {
    console.log('Initial');

    resolve();
})
.then(() => {
    throw new Error('Something failed');
        
    console.log('Do this'); // Never reached
})
.catch(() => {
    console.log('Something failed');
    throw new Error('Something failed again');
})
.catch((error) => {
    console.log('Final error : ', error.message);
});

Der zweite .catch()gibt ein Versprechen zurück, das erfüllt ist. Der .then()Handler kann aufgerufen werden:

new Promise((resolve, reject) => {
    console.log('Initial');

    resolve();
})
.then(() => {
    throw new Error('Something failed');
        
    console.log('Do this'); // Never reached
})
.catch(() => {
    console.log('Something failed');
    throw new Error('Something failed again');
})
.catch((error) => {
    console.log('Final error : ', error.message);
})
.then(() => {
    console.log('Show this message whatever happened before');
});

Nützliche Referenz: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#Chaining_after_a_catch

Hoffe das hilft!

Philippe Sultan
quelle
4

Es gibt keinen wichtigen Unterschied, wenn Sie den catchMethodenaufruf vollständig weglassen.

Das einzige, was hinzugefügt wird, ist eine zusätzliche Mikrotask, was in der Praxis bedeutet, dass Sie die Ablehnung des Versprechens später bemerken als dies bei einem Versprechen der Fall ist, das ohne die catchKlausel fehlschlägt .

Das nächste Snippet zeigt dies:

var p;
// Case 1: with catch
p = Promise.reject('my error 1')
       .catch(function(error) {
          throw(error);
       });

p.catch( error => console.log(error) );
// Case 2: without catch
p = Promise.reject('my error 2');

p.catch( error => console.log(error) );

Beachten Sie, wie die zweite Ablehnung vor der ersten gemeldet wird. Das ist ungefähr der einzige Unterschied.

Trincot
quelle
4

Ihre Frage lautet also: "Was macht die .catch()Methode in der Versprechenskette ?"

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw

Die throw-Anweisung "stoppt (die Anweisungen nach dem throw werden nicht ausgeführt) und die Steuerung wird an den ersten catch-Block im Aufrufstapel übergeben. Wenn unter den Aufruferfunktionen kein catch-Block vorhanden ist, wird das Programm beendet."

In der Versprechenskette gibt die .then()Methode eine Art Datenblock zurück. Diese Rückgabe des Stücks wird das Versprechen vervollständigen. Die erfolgreiche Rückgabe der Daten vervollständigt das Versprechen. Sie können sich die .catch()Methode genauso vorstellen. .catch()Es werden jedoch erfolglose Datenabrufe verarbeitet. Die throw-Anweisung vervollständigt das Versprechen. Gelegentlich werden Sie Entwickler sehen, .catch((err) => {console.log(err))} die auch die Versprechenskette vervollständigen.

Matt Fernandez
quelle
0

Sie müssen es tatsächlich nicht erneut werfen. Lassen Sie Promise.catch einfach leer, da es sonst als nicht behandelt betrachtet wird, und verpacken Sie den Code in einen Try-Catch. Der Fehler wird automatisch abgefangen.

try{
  promise.then(function(result){
    //some code
  }).catch(function(error) {
    //no need for re throwing or any coding. but leave this as this otherwise it will consider as un handled
  });
}catch(e){
  console.log(e);
  //error can handle in here
}
Aylian Craspa
quelle