2017-02-02 1 views
21

Ich habe Schwierigkeiten zu verstehen, den Unterschied zwischen setzen .catch vor und nach dann in einem verschachtelten Versprechen.Platzierung der Fang vor und nach dann

Alternative 1:

test1Async(10).then((res) => { 
    return test2Async(22) 
    .then((res) => { 
     return test3Async(100); 
    }).catch((err) => { 
     throw "ERROR AFTER THEN"; 
    }); 
}).then((res) => { 
    console.log(res); 
}).catch((err) => { 
    console.log(err); 
}); 

Alternative 2:

test1Async(10).then((res) => { 
    return test2Async(22) 
    .catch((err) => { 
     throw "ERROR BEFORE THEN"; 
     }) 
     .then((res) => { 
     return test3Async(100); 
     }); 
    }).then((res) => { 
    console.log(res); 
    }).catch((err) => { 
    console.log(err); 
    }); 

Das Verhalten der einzelnen Funktionen ist wie folgt, test1 fehlschlagen, wenn Nummer <0 test2 schlägt fehl, wenn Nummer > 10 und test3 schlägt fehl, wenn Nummer ist nicht 100. In diesem Fall ist test2 nur fehlgeschlagen.

Ich habe versucht, zu starten und test2Async fehlschlagen, beide vor und nach dem Verhalten verhält sich dann auf die gleiche Weise, und das führt nicht zu test3Async. Kann mir jemand den Hauptunterschied erklären, wenn man an verschiedenen Orten Fänge platziert?

In jeder Funktion I , um zu überprüfen, ob es ausgeführt wird.

Diese Frage entsteht wegen des vorherigen Threads, den ich How to turn nested callback into promise? bekannt gab. Ich denke, es ist ein anderes Problem und es lohnt sich, ein anderes Thema zu veröffentlichen.

+0

Sowohl .then als auch .catch können das Versprechen ändern ... also bin ich mir nicht sicher, woher das Missverständnis kommt. Wenn Sie fangen vor dem. Dann, fangen sie Ablehnungen, die vor der. Dann und die dann ausgeführt wird es ist/fail Callbacks basierend auf, was passiert innerhalb der .Catch, und umgekehrt, wenn Sie sie tauschen. –

+0

Sorry, wenn meine Frage nicht klar war. Aber in diesem Fall verhalten sich beide Fälle gleich, so dass ich den Unterschied nicht sehen kann. Kannst du mir sagen, wann wir VORHER den Fang fangen und wann wir uns danach entschieden haben? es danach zu setzen scheint wirklich intuitiv und üblich. Nur nicht sicher, warum manchmal wir es vor dann setzen – Zanko

+0

Wenn sie das gleiche durchführen, ist es einfach, weil das, was jeder tut, das Ergebnis in diesem speziellen Fall nicht ändert. Eine geringfügige Änderung könnte das Ergebnis verändern. –

Antwort

45

Also, im Grunde Sie fragen, was ist der Unterschied zwischen diesen beiden (wo p ist ein Versprechen aus einem früheren Code erstellt):

return p.then(...).catch(...); 

und

return p.catch(...).then(...); 

Es gibt Unterschiede entweder wenn p auflöst oder ablehnt, hängt es von dem ab, was der Code in den Handlern .then() oder .catch() tut.

Was, wenn p löst passiert: genannt wird

Im ersten Schema, wenn p Entschlüssen, die .then() Handler. Wenn der -Handler entweder einen Wert oder ein anderes Versprechen zurückgibt, das schließlich verrechnet wird, wird der .catch() -Handler übersprungen. Wenn jedoch der Handler entweder ein Versprechen zurückgibt oder zurückgibt, das schließlich ablehnt, wird der Handler .catch() sowohl für eine Zurückweisung im ursprünglichen Versprechen p als auch für einen Fehler im Handler ausgeführt.

Im zweiten Schema, wenn p löst, wird der Handler aufgerufen. Wenn der Handler entweder ein Versprechen zurückgibt oder zurückgibt, das schließlich zurückweist, kann der Handler .catch() den Fehler nicht abfangen, weil er zuvor in der Kette vorhanden ist.

Also, das ist der Unterschied # 1. Wenn der Handler .catch() AFTER ist, kann er auch Fehler innerhalb des -Handlers erkennen.

Was passiert, wenn p ablehnt:

nun in dem ersten Schema, wenn das Versprechen p ablehnt, dann wird der .then() Handler übersprungen und die .catch() Handler werden aufgerufen, wie man es erwarten würde. Was Sie im Handler .catch() tun, bestimmt, was als Endergebnis zurückgegeben wird. Wenn Sie einfach einen Wert aus dem Handler .catch() zurückgeben oder eine Versprechung zurückgeben, die schließlich verrechnet wird, wechselt die Versprechungskette in den aufgelösten Status, weil Sie den Fehler "behandelt" und normal zurückgegeben haben. Wenn Sie ein abgelehntes Versprechen im Handler .catch() werfen oder zurückgeben, bleibt das zurückgegebene Versprechen zurückgewiesen.

Im zweiten Schema, wenn das Versprechen zurückweist, dann wird der .catch() Handler aufgerufen. Wenn Sie einen normalen Wert oder eine Zusage zurückgeben, die schließlich vom Handler .catch() aufgelöst wird (also den Fehler "behandelt"), wechselt die Versprechungskette in den aufgelösten Zustand und der .then() Handler nach dem .catch() wird aufgerufen.

Also das ist der Unterschied # 2. Wenn der Handler .catch() BEFORE ist, kann er den Fehler behandeln und ermöglichen, dass der Handler immer noch aufgerufen wird.

Wann welche:

das erste Schema verwenden, wenn Sie nur eine .catch() Handler möchten, dass Fehler in entweder dem Urverheißung p oder in der .then() Handler und ein Zurückweisungs von p sollte die .then() Handler überspringen fangen .

Verwenden Sie das zweite Schema, wenn Sie Fehler in der ursprünglichen Verheißung p abfangen möchten und (abhängig von den Bedingungen) möglicherweise zulassen, dass die Versprechenskette als gelöst fortfährt, und so den -Handler ausführt.

Die andere Option

gibt es noch eine andere Möglichkeit, beide Rückrufe zu verwenden, die Sie .then() nach passieren kann:

p.then(fn1, fn2) 

Dies garantiert, dass nur eine von fn1 oder fn2 jemals aufgerufen werden. Wenn aufgelöst wird, wird fn1 aufgerufen. Wenn zurückgewiesen wird, wird fn2 aufgerufen. Keine Änderung des Ergebnisses in fn1 kann jemals fn2 aufrufen oder umgekehrt werden. Wenn Sie also absolut sicher gehen wollen, dass nur einer Ihrer beiden Handler aufgerufen wird, unabhängig davon, was in den Handlern selbst geschieht, können Sie p.then(fn1, fn2) verwenden.

+0

Die Frage bezieht sich speziell auf die Reihenfolge von '.then()' und '.catch()', die Sie beantworten. Außerdem gibst du ein paar Tipps, wann du welche Reihenfolge verwenden sollst, wobei es meiner Ansicht nach angebracht ist, eine dritte Option zu erwähnen, nämlich sowohl den Erfolgs- als auch den Fehler-Handler an [.then()] zu übergeben (https://developer.mozilla.org/ de-DE/docs/Web/JavaScript/Referenz/Globale_Objekte/Versprechen/dann # Parameter). In diesem Fall wird höchstens ein Handler aufgerufen. – ArneHugo

+0

@ArneHugo - Guter Vorschlag. Ich fügte hinzu. – jfriend00

2

jfriend00's answer ist ausgezeichnet, aber ich dachte, es wäre eine gute Idee, den analogen synchronen Code hinzuzufügen.

return p.then(...).catch(...); 

ist ähnlich der Synchron:

try { 
    iMightThrow() // like `p` 
    then() 
} catch (err) { 
    handleCatch() 
} 

Wenn iMightThrow() nicht wirft, wird then() genannt werden.Wenn es wirft (oder wenn then() selbst wirft), wird handleCatch() aufgerufen. Beachten Sie, dass der catch Block keine Kontrolle darüber hat, ob then aufgerufen wird oder nicht.

Auf der anderen Seite,

return p.catch(...).then(...); 

ist auf die Synchron ähnlich:

try { 
    iMightThrow() 
} catch (err) { 
    handleCatch() 
} 

then() 

In diesem Fall, wenn iMightThrow() nicht werfen, führen then() dann. Wenn es weht, dann wäre es bis handleCatch() zu entscheiden, ob then() aufgerufen wird, denn wenn handleCatch() erneut aufruft, dann wird then() nicht aufgerufen, da die Ausnahme sofort dem Anrufer übergeben wird. Wenn das Problem mit handleCatch() behoben werden kann, wird then() aufgerufen.

Verwandte Themen