Szukaj…
Składnia
- spróbuj {…} catch (error) {…}
- spróbuj {…} wreszcie {…}
- spróbuj {…} złapać (błąd) {…} wreszcie {…}
- wyślij nowy błąd ([komunikat]);
- błąd wyrzucenia ([komunikat]);
Uwagi
try
pozwala zdefiniować blok kodu, który będzie testowany pod kątem błędów podczas jego wykonywania.
catch
pozwala zdefiniować blok kodu do wykonania, jeśli wystąpi błąd w bloku try
.
finally
pozwala wykonać kod niezależnie od wyniku. Uważaj jednak, instrukcje przepływu bloków try i catch zostaną zawieszone do czasu zakończenia wykonywania bloku ostatecznie.
Interakcja z obietnicami
Wyjątkiem jest kod synchroniczny, a odrzucenia - obietnica oparta na kodzie asynchronicznym. Jeśli wyjątek zostanie zgłoszony w module obsługi obietnicy, jego błąd zostanie automatycznie przechwycony i użyty do odrzucenia obietnicy.
Promise.resolve(5)
.then(result => {
throw new Error("I don't like five");
})
.then(result => {
console.info("Promise resolved: " + result);
})
.catch(error => {
console.error("Promise rejected: " + error);
});
Promise rejected: Error: I don't like five
Propozycja funkcji asynchronicznych - która ma być częścią ECMAScript 2017 - rozszerza to w przeciwnym kierunku. Jeśli czekasz na odrzuconą obietnicę, jej błąd jest zgłaszany jako wyjątek:
async function main() {
try {
await Promise.reject(new Error("Invalid something"));
} catch (error) {
console.log("Caught error: " + error);
}
}
main();
Caught error: Invalid something
Obiekty błędów
Błędy czasu wykonania w JavaScript są instancjami obiektu Error
. Obiekt Error
może być również używany jako taki lub jako podstawa wyjątków zdefiniowanych przez użytkownika. Możliwe jest wyrzucenie dowolnego typu wartości - na przykład ciągów - ale zdecydowanie zalecamy użycie Error
lub jednego z jego pochodnych, aby zapewnić prawidłowe zachowanie informacji debugowania - np. Śladów stosu.
Pierwszym parametrem konstruktora Error
jest czytelny dla człowieka komunikat o błędzie. Powinieneś zawsze próbować podać przydatny komunikat o błędzie dotyczący tego, co poszło źle, nawet jeśli dodatkowe informacje można znaleźć gdzie indziej.
try {
throw new Error('Useful message');
} catch (error) {
console.log('Something went wrong! ' + error.message);
}
Kolejność operacji i zaawansowane myśli
Bez bloku try catch niezdefiniowane funkcje będą zgłaszać błędy i zatrzymywać wykonywanie:
undefinedFunction("This will not get executed");
console.log("I will never run because of the uncaught error!");
Zgłasza błąd i nie uruchamia drugiej linii:
// Uncaught ReferenceError: undefinedFunction is not defined
Potrzebujesz bloku try catch, podobnego do innych języków, aby upewnić się, że złapałeś ten błąd, aby kod mógł nadal wykonywać:
try {
undefinedFunction("This will not get executed");
} catch(error) {
console.log("An error occured!", error);
} finally {
console.log("The code-block has finished");
}
console.log("I will run because we caught the error!");
Teraz wykryliśmy błąd i możemy być pewni, że nasz kod zostanie wykonany
// An error occured! ReferenceError: undefinedFunction is not defined(…)
// The code-block has finished
// I will run because we caught the error!
Co jeśli wystąpi błąd w naszym bloku catch !?
try {
undefinedFunction("This will not get executed");
} catch(error) {
otherUndefinedFunction("Uh oh... ");
console.log("An error occured!", error);
} finally {
console.log("The code-block has finished");
}
console.log("I won't run because of the uncaught error in the catch block!");
Nie przetwarzamy reszty naszego bloku catch, a wykonanie zostanie zatrzymane, z wyjątkiem bloku w końcu.
// The code-block has finished
// Uncaught ReferenceError: otherUndefinedFunction is not defined(…)
Zawsze możesz zagnieżdżać bloki try catch. Ale nie powinieneś, bo będzie bardzo bałagan.
try {
undefinedFunction("This will not get executed");
} catch(error) {
try {
otherUndefinedFunction("Uh oh... ");
} catch(error2) {
console.log("Too much nesting is bad for my heart and soul...");
}
console.log("An error occured!", error);
} finally {
console.log("The code-block has finished");
}
console.log("I will run because we caught the error!");
Złapie wszystkie błędy z poprzedniego przykładu i zarejestruje następujące:
//Too much nesting is bad for my heart and soul...
//An error occured! ReferenceError: undefinedFunction is not defined(…)
//The code-block has finished
//I will run because we caught the error!
Jak więc wyłapać wszystkie błędy !? Dla niezdefiniowanych zmiennych i funkcji: nie możesz.
Nie powinieneś także zawijać wszystkich zmiennych i funkcji w blok try / catch, ponieważ są to proste przykłady, które pojawią się tylko raz, dopóki ich nie naprawisz. Jednak w przypadku obiektów, funkcji i innych zmiennych, o których wiesz, że istnieją, ale nie wiesz, czy będą istnieć ich właściwości, podprocesy lub skutki uboczne, lub spodziewasz się pewnych stanów błędów w pewnych okolicznościach, powinieneś wyodrębnić obsługę błędów w jakiś sposób. Oto bardzo prosty przykład i wdrożenie.
Bez chronionego sposobu wywoływania metod niezaufanych lub zgłaszania wyjątków:
function foo(a, b, c) {
console.log(a, b, c);
throw new Error("custom error!");
}
try {
foo(1, 2, 3);
} catch(e) {
try {
foo(4, 5, 6);
} catch(e2) {
console.log("We had to nest because there's currently no other way...");
}
console.log(e);
}
// 1 2 3
// 4 5 6
// We had to nest because there's currently no other way...
// Error: custom error!(…)
I z ochroną:
function foo(a, b, c) {
console.log(a, b, c);
throw new Error("custom error!");
}
function protectedFunction(fn, ...args) {
try {
fn.apply(this, args);
} catch (e) {
console.log("caught error: " + e.name + " -> " + e.message);
}
}
protectedFunction(foo, 1, 2, 3);
protectedFunction(foo, 4, 5, 6);
// 1 2 3
// caught error: Error -> custom error!
// 4 5 6
// caught error: Error -> custom error!
Wychwytujemy błędy i nadal przetwarzamy cały oczekiwany kod, choć z nieco inną składnią. Tak czy inaczej, zadziała, ale kiedy budujesz bardziej zaawansowane aplikacje, będziesz chciał zacząć myśleć o sposobach wyodrębnienia obsługi błędów.
Typy błędów
W JavaScript jest sześć konkretnych konstruktorów błędów podstawowych:
EvalError
- tworzy instancję reprezentującą błąd występujący w odniesieniu do funkcji globalnejeval()
.InternalError
- tworzy instancję reprezentującą błąd, który występuje, gdy zostanie zgłoszony błąd wewnętrzny w silniku JavaScript. Np. „Za dużo rekurencji”. (Obsługiwany tylko przez Mozilla Firefox )RangeError
- tworzy instancję reprezentującą błąd, który występuje, gdy zmienna liczbowa lub parametr jest poza swoim prawidłowym zakresem.ReferenceError
- tworzy instancję reprezentującą błąd, który występuje, gdy następuje odwołanie do niepoprawnego odwołania.SyntaxError
- tworzy instancję reprezentujący błąd składni, który występuje podczas analizowania kodu weval()
.TypeError
- tworzy instancję reprezentującą błąd, który występuje, gdy zmienna lub parametr nie jest poprawnego typu.URIError
- tworzy instancję reprezentujący błąd, który występuje, gdyencodeURI()
lubdecodeURI()
przekazywane są nieprawidłowe parametry.
Jeśli wdrażasz mechanizm obsługi błędów, możesz sprawdzić, jaki rodzaj błędu wychwytujesz z kodu.
try {
throw new TypeError();
}
catch (e){
if(e instanceof Error){
console.log('instance of general Error constructor');
}
if(e instanceof TypeError) {
console.log('type error');
}
}
W takim przypadku e
będzie wystąpieniem TypeError
. Wszystkie typy błędów rozszerzają podstawowy konstruktor Error
, dlatego jest to również instancja Error
.
Pamiętając o tym, pokazuje nam, że sprawdzanie e
jako wystąpienia Error
jest w większości przypadków bezużyteczne.