Obsługa błędów — program może zareagować
Błędny tekst nie musi kończyć całej aplikacji. Zdecyduj, gdzie zgłosić problem, gdzie go obsłużyć i kiedy prostszy będzie zwykły wynik operacji.
Po tej lekcji potrafisz
- Użyjesz throw, try, catch i finally.
- Sprawdzisz rodzaj złapanej wartości.
- Odróżnisz oczekiwany brak wyniku od sytuacji wyjątkowej.
Konfiguracja nie daje się odczytać
Program otrzymał tekst, który miał opisywać ustawienia, lecz ktoś usunął cudzysłów. Funkcja odczytująca może zgłosić błąd. Kod odpowiedzialny za kontakt z użytkownikiem powinien zdecydować, jaki komunikat pokazać.
Małe kroki, konkretne efekty
throw przerywa bieżącą drogę
throw zgłasza wyjątek i przerywa wykonywanie kolejnych instrukcji na tej drodze. Najbliższy pasujący catch może go przejąć. Rzucamy obiekt Error, żeby zachować wiadomość i informacje diagnostyczne.
function sprawdz(liczba: number): number {
if (!Number.isInteger(liczba) || liczba < 1) { throw new Error("Podaj dodatnią liczbę całkowitą"); }
return liczba;
}
try {
console.log(sprawdz(0));
} catch (blad) {
console.log(blad instanceof Error ? blad.message : "Nieznany błąd");
}
Podaj dodatnią liczbę całkowitą
Zmienna catch w trybie strict ma typ unknown. JavaScript pozwala rzucić również tekst lub inny obiekt, więc nie zakładaj automatycznie istnienia message.
finally wykonuje porządkowanie
finally działa po try lub catch, także przy return. Nie umieszczaj tam return: mógłby zastąpić wcześniejszy wynik lub ukryć wyjątek. Nie jest gwarancją działania po nagłym przerwaniu całego procesu.
try {
console.log("Rozpoczęto próbę");
throw new Error("Brak biletu");
} catch (blad) {
if (blad instanceof Error) { console.log(blad.message); }
} finally {
console.log("Próba zakończona");
}
Rozpoczęto próbę
Brak biletu
Próba zakończona
finally nie oznacza „udało się”. Ten sam komunikat końcowy wystąpi po sukcesie i po błędzie.
Czytanie ustawień gry
JSON.parse odczytuje tekst JSON i może zgłosić SyntaxError. Po odczycie sprawdzamy osobno kształt danych. Poprawna składnia nie gwarantuje poprawnego ustawienia.
function odczytajLimit(tekst: string): number {
const dane: unknown = JSON.parse(tekst);
if (typeof dane !== "object" || dane === null || !("limit" in dane)) {
throw new Error("Brak pola limit");
}
if (typeof dane.limit !== "number" || !Number.isInteger(dane.limit) || dane.limit < 1 || dane.limit > 16) {
throw new Error("Limit musi wynosić 1–16");
}
return dane.limit;
}
for (const tekst of ['{"limit":8}', '{"limit":99}', '{}']) {
try { console.log("Limit: " + odczytajLimit(tekst)); }
catch (blad) { console.log(blad instanceof Error ? blad.message : "Błąd odczytu"); }
}
Limit: 8
Limit musi wynosić 1–16
Brak pola limit
Jak program dochodzi do wyniku
- Odczyt JSON daje nieznane dane, dlatego zapisujemy unknown.
- Pierwszy warunek sprawdza obiekt, wyklucza null i kontroluje obecność pola.
- Następny sprawdza rodzaj oraz zakres wartości.
- Każda próba ma osobny try, więc błędna konfiguracja nie zatrzymuje następnej próby.
Zanim przejdziesz dalej
Czy catch uruchomi się dla poprawnego limitu 8?
Sprawdź swoje rozumowanie
Nie. Po prawidłowym zakończeniu try program przechodzi dalej; catch służy do obsługi zgłoszonego wyjątku.
Zmień kod i zobacz, co się stanie
Własna klasa błędu i decyzja o obsłudze
Osobna klasa błędu pozwala odróżnić znany problem od nieoczekiwanej awarii. Obsłuż to, co rozumiesz, a nieznany wyjątek przekaż dalej.
class BrakMonet extends Error {}
function kup(saldo: number): void {
if (saldo < 10) { throw new BrakMonet("Potrzebujesz 10 monet"); }
}
try { kup(5); }
catch (blad) {
if (blad instanceof BrakMonet) { console.log(blad.message); }
else { throw blad; }
}
Potrzebujesz 10 monet
Brak środków można też opisać unią { ok: false, … }, szczególnie gdy to częsty, oczekiwany wynik. Wyjątki nie muszą zastępować wszystkich warunków.
Gdy wynik zaskakuje
| Pomyłka | Co się dzieje i jak to poprawić |
|---|---|
| Pusty catch | Program ukrywa przyczynę problemu. Obsłuż błąd świadomie albo przekaż dalej. |
| Odczyt blad.message bez sprawdzenia | Złapana wartość może nie być Error. |
| Return w finally | Może nadpisać wcześniejszy wynik i ukryć błąd. |
JSON.parse jako źródło błędu
Metoda JSON.parse zamienia tekst na dane i zgłasza błąd, gdy tekst nie jest poprawnym
JSON-em. Używamy jej tutaj właśnie dlatego — to najkrótszy sposób na wywołanie prawdziwego wyjątku.
Samym formatem JSON i sprawdzaniem kształtu danych zajmuje się lekcja
29.
Teraz Twoja kolej
Rozwiązanie jest jedną z możliwości. Zanim je odkryjesz, uruchom własną wersję dla podanych danych i przynajmniej jednego przypadku brzegowego.
Napisz dziel, która przy b = 0 zgłasza Error z komunikatem „Nie dziel przez zero”. Sprawdź 10 / 2 i 10 / 0.
Mała podpowiedź
JavaScript sam nie rzuci wyjątku dla dzielenia number przez zero.
Przykładowe rozwiązanie z wyjaśnieniem
function dziel(a: number, b: number): number {
if (b === 0) { throw new Error("Nie dziel przez zero"); }
return a / b;
}
console.log(dziel(10, 2));
try { dziel(10, 0); } catch (e) { if (e instanceof Error) { console.log(e.message); } }
5
Nie dziel przez zero
To reguła naszego programu, a nie automatyczne zachowanie operatora /.
Spróbuj odczytać tekst „nie-json”. Przechwyć błąd i wypisz stały komunikat „Nie udało się odczytać”.
Mała podpowiedź
Treść komunikatu silnika może się różnić; własny komunikat pozostaje przewidywalny.
Przykładowe rozwiązanie z wyjaśnieniem
try { JSON.parse("nie-json"); }
catch { console.log("Nie udało się odczytać"); }
Nie udało się odczytać
Nie potrzebujemy zmiennej błędu, gdy świadomie pokazujemy ogólny komunikat.
Sprawdź [2, -1, 4]. Dodatnią wartość wypisz, niedodatnią zgłoś jako błąd. Trzecia próba nadal ma się wykonać.
Mała podpowiedź
try umieść wewnątrz pętli.
Przykładowe rozwiązanie z wyjaśnieniem
for (const n of [2, -1, 4]) {
try {
if (n <= 0) { throw new Error("Błędna liczba"); }
console.log(n);
} catch (e) { if (e instanceof Error) { console.log(e.message); } }
}
2
Błędna liczba
4
Umiejscowienie try określa, jak duży fragment pracy przerywa wyjątek.
Napisz funkcję proba, która zgłasza i obsługuje błąd „Odmowa”, a w finally wypisuje „Koniec”. Na końcu funkcja zwraca false.
Mała podpowiedź
Return pozostaw poza finally.
Przykładowe rozwiązanie z wyjaśnieniem
function proba(): boolean {
try { throw new Error("Odmowa"); }
catch (e) { if (e instanceof Error) { console.log(e.message); } }
finally { console.log("Koniec"); }
return false;
}
console.log(proba());
Odmowa
Koniec
false
Porządkowanie i decyzja o wyniku są oddzielone.
Co zabierasz do następnej lekcji
- throw zgłasza wyjątek, catch go przejmuje, finally służy porządkowaniu.
- Zmienną catch sprawdzaj jak unknown.
- Nie każdy brak wyniku wymaga wyjątku.