Wyjątki w łańcuchach Promise w JavaScript
Zakładając, że z jakichś powodów nasz Promise zakończy się błędem:
let promise = new Promise(function(resolve, reject) {
setTimeout(function() {
reject('error');
}, 3000);
});
W tym przypadku wykonanie kodu natychmiast przejdzie
do tego then, w którym znajduje się funkcja obsługi
błędu, albo do pierwszego catch, w zależności
od tego, co zostanie napotkane wcześniej.
Oto przykład pierwszej sytuacji:
promise.then(
function(result) {
return result + '1';
}
).then(
function(result) {
return result + '2';
},
function(error) {
// wykonanie natychmiast przejdzie tutaj
}
).then(
function(result) {
console.log(result);
}
);
Oto przykład drugiej sytuacji:
promise.then(
function(result) {
return result + '1';
}
).then(
function(result) {
return result + '2';
}
).catch(
function(error) {
// wykonanie natychmiast przejdzie tutaj
}
).then(
function(result) {
console.log(result);
}
);
Funkcja obsługi ma dwie możliwości działania:
jeśli poradziła sobie z sytuacją wyjątkową,
może zwrócić wynik przez return
i wykonanie będzie kontynuowane dalej wzdłuż łańcucha.
Jeśli jednak nie poradziła sobie z błędem, może
albo nic nie zwrócić, albo rzucić wyjątek
przez throw. W tym przypadku wykonanie
przejdzie do następnego przechwytywacza błędów
(w then lub catch - cokolwiek napotkane
wcześniej).
Z reguły wszystkie błędy łańcucha są przechwytywane
w jednym miejscu: na końcu łańcucha umieszczany jest
catch:
promise.then(
function(result) {
return result + '1';
}
).then(
function(result) {
return result + '2';
}
).catch(
function(error) {
// trafimy tutaj w przypadku błędu
}
);
Przy tym wyjątek może powstać w samym
Promise, albo być rzucony przez throw
w dowolnym ogniwie łańcucha:
promise.then(
function(result) {
return result + '1';
}
).then(
function(result) {
if (wszystkoDobrze) {
return result + '2';
} else {
throw new Error('błąd'); // przechodzimy do najbliższego przechwytywacza
}
}
)
.then(
function(result) {
return result + '3';
}
).catch(
function(error) {
// najbliższy przechwytywacz
}
);
Pamiętaj, że catch jest potrzebny właśnie do
diagnozowania błędu: czy jest on rozwiązywalny, czy nie.
Jeśli błąd jest rozwiązywalny, to catch powinien
przekazać jego rozwiązanie następnemu za sobą then.
A jeśli nie jest rozwiązywalny (lub dany catch
po prostu nie wie, jak go rozwiązać), to powinniśmy
albo nic nie zwrócić, albo rzucić wyjątek:
promise.then(
function(result) {
return result + '1';
}
).then(
function(result) {
return result + '2';
}
).catch(
function(error) {
if (bladRozwiazywalny) {
return 'dane'; // wysyłamy do następnego then
} else {
// nic nie zwracamy lub rzucamy wyjątek
}
}
).then(
function(result) {
// tutaj rozwiązujemy błąd
}
);