Mam problem ze zrozumieniem różnicy między wstawieniem .catch
PRZED i PO następnie w zagnieżdżonej obietnicy.
Alternatywa 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);
});
Alternatywa 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);
});
Zachowanie każdej funkcji jest następujące, test1 <0
kończy się niepowodzeniem, jeśli number to test2, nie powiedzie się, jeśli number to, > 10
a test3 nie powiedzie się, jeśli number nie 100
. W tym przypadku test2 kończy się niepowodzeniem.
Próbowałem uruchomić i spowodować niepowodzenie testu test2Async, zarówno PRZED, jak i PO, a następnie zachowuje się w ten sam sposób, co nie oznacza wykonania testu test3Async. Czy ktoś może mi wyjaśnić główną różnicę w umieszczaniu połowu w różnych miejscach?
W każdej funkcji I console.log('Running test X')
, aby sprawdzić, czy zostanie wykonana.
To pytanie pojawia się z powodu poprzedniego wątku, który opublikowałem Jak zamienić zagnieżdżone wywołanie zwrotne w obietnicę? . Myślę, że to inny problem i warto zgłosić inny temat.
źródło
Odpowiedzi:
Więc w zasadzie pytasz, jaka jest różnica między tymi dwoma (gdzie
p
jest obietnica utworzona z jakiegoś poprzedniego kodu):i
Istnieją różnice, gdy p rozwiązuje lub odrzuca, ale to, czy te różnice mają znaczenie, czy nie, zależy od tego, co robi kod wewnątrz
.then()
lub.catch()
procedury obsługi.Co się stanie, gdy zostanie
p
rozwiązany:W pierwszym schemacie, po
p
rozwiązaniu,.then()
wywoływana jest procedura obsługi. Jeśli ten.then()
program obsługi zwróci wartość lub inną obietnicę, która ostatecznie zostanie rozwiązana, wówczas.catch()
procedura obsługi jest pomijana. Ale jeśli przewodnik.then()
albo wyrzuci lub zwróci obietnicę, która ostatecznie ją odrzuci, wówczas program.catch()
obsługi wykona zarówno odrzucenie w pierwotnej obietnicyp
, jak i błąd, który wystąpi w programie.then()
obsługi.W drugim schemacie, po
p
rozwiązaniu,.then()
wywoływana jest procedura obsługi. Jeśli ten przewodnik.then()
rzuca lub zwraca obietnicę, która ostatecznie odrzuca,.catch()
nie może jej złapać, ponieważ znajduje się przed nią w łańcuchu.Więc to jest różnica # 1. Jeśli program
.catch()
obsługi jest AFTER, może również wychwycić błędy wewnątrz.then()
obsługi.Co się dzieje, gdy
p
odrzuca:Teraz, w pierwszym schemacie, jeśli obietnica zostanie
p
odrzucona, to program.then()
obsługi jest pomijany, a program.catch()
obsługi zostanie wywołany tak, jak można się tego spodziewać. To, co robisz w.catch()
procedurze obsługi, określa, co zostanie zwrócone jako wynik końcowy. Jeśli po prostu zwrócisz wartość z.catch()
procedury obsługi lub zwrócisz obietnicę, która w końcu zostanie rozwiązana, wówczas łańcuch obietnic przełącza się do stanu rozwiązanego, ponieważ „obsłużyłeś” błąd i powróciłeś normalnie. Jeśli wyrzucisz lub zwrócisz odrzuconą obietnicę do przewodnika.catch()
, wówczas zwrócona obietnica pozostaje odrzucona.W drugim schemacie, jeśli obietnica zostanie
p
odrzucona,.catch()
wywoływany jest przewodnik. Jeśli zwrócisz normalną wartość lub obietnicę, która ostatecznie zostanie rozwiązana przez.catch()
procedurę obsługi (w ten sposób „obsłuży” błąd), wówczas łańcuch obietnicy przełącza się do stanu rozwiązanego, a.then()
procedura obsługi po zakończeniu.catch()
zostanie wywołana.Więc to jest różnica # 2. Jeśli
.catch()
procedura obsługi jest PRZED, to może obsłużyć błąd i pozwolić, aby.then()
procedura obsługi nadal była wywoływana.Kiedy używać których:
Użyj pierwszego schematu, jeśli chcesz, aby tylko jeden
.catch()
program obsługi mógł wychwycić błędy w oryginalnej obietnicyp
lub w.then()
module obsługi, a odrzucenie z programup
powinno pominąć.then()
procedurę obsługi.Użyj drugiego schematu, jeśli chcesz być w stanie wychwycić błędy w pierwotnej obietnicy
p
i być może (w zależności od warunków), pozwolić łańcuchowi obietnic na kontynuację po rozwiązaniu, wykonując w ten sposób.then()
procedurę obsługi.Druga opcja
Jest jeszcze jedna opcja korzystania z obu wywołań zwrotnych, do których możesz przejść
.then()
jak w:Gwarantuje to, że tylko jeden z
fn1
lubfn2
kiedykolwiek zostanie wywołany. Jeślip
ustąpi,fn1
zostanie wezwany. Jeślip
odrzuci,fn2
zostanie wezwany. Żadna zmiana wynikufn1
nie może sprawić,fn2
że ktoś Cię wezwie lub odwrotnie. Tak więc, jeśli chcesz mieć absolutną pewność, że tylko jeden z twoich dwóch programów obsługi jest wywoływany, niezależnie od tego, co dzieje się w samych modułach obsługi, możesz użyćp.then(fn1, fn2)
.źródło
.then()
i.catch()
, na które odpowiadasz. Dodatkowo dajesz kilka wskazówek, kiedy użyć jakiej kolejności, gdzie myślę, że należy wspomnieć o trzeciej opcji, a mianowicie o przekazaniu zarówno procedury obsługi sukcesu, jak i błędu do .then () . W takim przypadku zostanie wywołany co najwyżej jeden program obsługi.Promise.reject(new Error("F")).then(x => x).catch(e => {console.log(e); return [1]}).then(console.log)
iPromise.resolve([2]).then(x => x).catch(e => [1]).then(console.log)
.then(this.setState({isModalOpen: false}))
. Nie przekazujesz odwołania do funkcji, aby.then()
kod w parenach był wykonywany natychmiast (zanim obietnica zostanie rozwiązana). Tak powinno być.then(() => this.setState({isModalOpen: false}))
.Odpowiedź jfriend00 jest doskonała, ale pomyślałem, że dobrym pomysłem byłoby dodanie analogicznego kodu synchronicznego.
jest podobny do synchronicznego:
Jeśli
iMightThrow()
nie wyrzuci,then()
zostanie wezwany. Jeśli rzuca (lub jeślithen()
sam rzuca),handleCatch()
zostanie wywołany. Zwróć uwagę, żecatch
blok nie ma kontroli nad tym, czythen
jest wywoływany, czy nie .Z drugiej strony,
jest podobny do synchronicznego:
W tym przypadku, jeśli
iMightThrow()
nie rzuci, tothen()
wykona. Jeśli tak, to należałobyhandleCatch()
zdecydować, czythen()
zostanie wywołany, ponieważ jeślihandleCatch()
powtórzy, tothen()
nie zostanie wywołany, ponieważ wyjątek zostanie natychmiast wyrzucony do wywołującego. Jeśli zhandleCatch()
wdziękiem poradzi sobie z problemem,then()
zostanie wywołany.źródło
then()
w afinally{...}
then()
wfinally{...}
, nie byłoby nieprawidłowo nazwać nawet jeślihandleCatch()
rzuca? Pamiętaj, że moim celem było pokazanie analogicznego kodu synchronicznego, a nie zasugerowanie różnych sposobów obsługi wyjątków