Ich habe Schwierigkeiten, den Unterschied zwischen Putten zu verstehen .catch
BEFORE und AFTER dann in einem verschachtelten Promise.
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 jeder Funktion ist wie folgt, test1 schlägt fehl, wenn Zahl ist <0
test2 schlägt fehl, wenn Zahl ist > 10
und test3 schlägt fehl, wenn Zahl nicht ist 100
. In diesem Fall schlägt nur test2 fehl.
Ich habe versucht, test2Async auszuführen und zum Scheitern zu bringen, sowohl BEFORE als auch AFTER verhalten sich dann gleich und das führt nicht zu test3Async. Kann mir jemand den Hauptunterschied für das Platzieren von Fang an verschiedenen Orten erklären?
In jeder Funktion I console.log('Running test X')
um zu prüfen, ob es ausgeführt wird.
Diese Frage stellt sich aufgrund des vorherigen Threads, den ich gepostet habe. How to turn nested callback into Promise?. Ich denke, es ist ein anderes Problem und es lohnt sich, ein anderes Thema zu posten.
Im Grunde fragen Sie also, was der Unterschied zwischen diesen beiden ist (wo p
ist ein Versprechen, das aus einem früheren Code erstellt wurde):
return p.then(...).catch(...);
und
return p.catch(...).then(...);
Es gibt Unterschiede, wenn p auflöst oder ablehnt, aber ob diese Unterschiede eine Rolle spielen oder nicht, hängt davon ab, was der Code in enthält .then()
oder .catch()
Handler tut.
Was passiert, wenn p
löst:
Im ersten Schema, wann p
beschließt, die .then()
Handler wird gerufen. Wenn das .then()
-Handler gibt entweder einen Wert oder ein anderes Promise zurück, das schließlich aufgelöst wird, und dann die .catch()
Handler wird übersprungen. Aber wenn die .then()
Der Handler löst entweder ein Promise aus oder gibt es zurück, das schließlich abgelehnt wird .catch()
Der Handler führt für beide eine Ablehnung im ursprünglichen Promise aus p
sondern auch ein Fehler, der in der auftritt .then()
Handler.
Im zweiten Schema, wann p
beschließt, die .then()
Handler wird gerufen. Wenn das .then()
Der Handler löst entweder ein Promise aus oder gibt es zurück, das schließlich abgelehnt wird .catch()
Der Handler kann das nicht abfangen, weil es in der Kette davor steht.
Das ist also der Unterschied Nr. 1. Wenn die .catch()
handler AFTER ist, dann kann er auch Fehler innerhalb der abfangen .then()
Handler.
Was passiert, wenn p
lehnt ab:
Nun, im ersten Schema, wenn das Versprechen p
ablehnt, dann die .then()
Handler wird übersprungen und die .catch()
handler wird aufgerufen, wie Sie es erwarten würden. Was machst du in der .catch()
Der Handler bestimmt, was als Endergebnis zurückgegeben wird. Wenn Sie nur einen Wert aus der zurückgeben .catch()
Handler ausführen oder ein Promise zurückgeben, das schließlich aufgelöst wird, dann wechselt die Promise-Kette in den gelösten Zustand, weil Sie den Fehler “behandelt” haben und normal zurückgekehrt sind. Wenn Sie ein abgelehntes Versprechen in die werfen oder zurückgeben .catch()
Handler, dann bleibt das zurückgegebene Versprechen abgelehnt.
Im zweiten Schema, wenn das Versprechen p
ablehnt, dann die .catch()
Handler wird gerufen. Wenn Sie einen normalen Wert oder ein Versprechen zurückgeben, löst sich das schließlich aus der .catch()
handler (also den Fehler “behandeln”), dann wechselt die Promise-Kette in den aufgelösten Zustand und die .then()
Handler nach dem .catch()
wird angerufen werden.
Das ist also der Unterschied Nr. 2. Wenn die .catch()
handler VOR ist, dann kann er den Fehler behandeln und das zulassen .then()
Handler noch angerufen werden.
Wann welche verwenden:
Verwenden Sie das erste Schema, wenn Sie nur eines möchten .catch()
Handler, der Fehler im ursprünglichen Promise abfangen kann p
oder im .then()
Handler und eine Ablehnung von p
sollte das überspringen .then()
Handler.
Verwenden Sie das zweite Schema, wenn Sie Fehler im ursprünglichen Promise abfangen möchten p
und vielleicht (abhängig von den Bedingungen) der Promise-Kette erlauben, wie aufgelöst fortzufahren, wodurch die ausgeführt wird .then()
Handler.
Die andere Option
Es gibt eine weitere Option, um beide Rückrufe zu verwenden, an die Sie übergeben können .then()
wie in:
p.then(fn1, fn2)
Dies garantiert, dass nur einer von fn1
oder fn2
wird jemals angerufen. Wenn p
löst sich dann auf fn1
wird angerufen werden. Wenn p
lehnt dann ab fn2
wird angerufen werden. Keine Ergebnisänderung in fn1
jemals machen kann fn2
angerufen werden oder umgekehrt. Wenn Sie also absolut sicherstellen möchten, dass nur einer Ihrer beiden Handler aufgerufen wird, unabhängig davon, was in den Handlern selbst passiert, können Sie verwenden p.then(fn1, fn2)
.
Die Antwort von jfriend00 ist ausgezeichnet, aber ich dachte, es wäre eine gute Idee, den analogen synchronen Code hinzuzufügen.
return p.then(...).catch(...);
ist ähnlich dem synchronen:
try {
iMightThrow() // like `p`
then()
} catch (err) {
handleCatch()
}
Wenn iMightThrow()
wirft nicht, then()
wird angerufen werden. Wenn es wirft (oder wenn then()
selbst wirft), dann handleCatch()
wird angerufen werden. Beachten Sie, wie die catch
Block hat keine Kontrolle darüber, ob oder nicht then
wird genannt.
Auf der anderen Seite,
return p.catch(...).then(...);
ist ähnlich dem synchronen:
try {
iMightThrow()
} catch (err) {
handleCatch()
}
then()
In diesem Fall, wenn iMightThrow()
wirft dann nicht then()
wird ausführen. Wenn es wirft, dann wäre es bis zu handleCatch()
zu entscheiden, ob then()
heißt, denn wenn handleCatch()
wirft dann zurück then()
wird nicht aufgerufen, da die Ausnahme sofort an den Aufrufer geworfen wird. Wenn handleCatch()
kann das Problem dann anmutig behandeln then()
wird angerufen werden.
Sowohl .then als auch .catch können das Versprechen ändern … also bin ich mir nicht sicher, woher das Missverständnis kommt. Wenn Sie catch vor das .then setzen, werden Ablehnungen abgefangen, die vor dem .then aufgetreten sind, und das .then führt seine Done/Fail-Callbacks basierend auf dem aus, was innerhalb des .catch passiert, und umgekehrt, wenn Sie sie austauschen.
– Kevin B
2. Februar 2017 um 22:02 Uhr
Entschuldigung, wenn meine Frage nicht klar war. Aber wie gesagt, in diesem Fall verhalten sich beide Fälle gleich, sodass ich den Unterschied nicht erkennen kann. Können Sie mir sagen, wann wir catch VORHER und wann wir uns entschieden haben, es NACHHER zu setzen? es danach zu setzen, scheint wirklich intuitiv und üblich zu sein. Ich bin mir nur nicht sicher, warum wir es manchmal davor setzen
– Zanko
2. Februar 2017 um 22:05 Uhr
Wenn sie die gleiche Leistung erbringen, liegt das einfach daran, dass das, was jeder tut, das Ergebnis in diesem speziellen Fall nicht verändert. Eine geringfügige Änderung an einem der beiden könnte das Ergebnis verändern.
– Kevin B
2. Februar 2017 um 22:06 Uhr
Was meinst du mit “Ändern des Ergebnisses”. Entschuldigung, ich bin wirklich verwirrt, haha
– Zanko
2. Februar 2017 um 22:15 Uhr
Wenn Sie zum Beispiel, anstatt einen Fehler zu werfen, einfach nichts getan haben, würde das Versprechen von „Abgelehnt“ zu „Aufgelöst“ wechseln. Das würde natürlich das Ergebnis verändern, denn das Versprechen ist jetzt ein eingelöstes Versprechen und kein zurückgewiesenes. (es sei denn natürlich, es wurde bereits gelöst, in diesem Fall wäre der Fang sowieso nicht gelaufen)
– Kevin B
2. Februar 2017 um 22:20 Uhr