Welcome to Our Website

błędy niestandardowe, Rozszerzanie błędów

Kiedy coś rozwijamy, często potrzebujemy własnych klas błędów, aby odzwierciedlić konkretne rzeczy, które mogą pójść nie tak w naszych zadaniach. Dla błędów w operacjach sieciowych możemy potrzebować HttpError , dla operacji bazodanowych DbError, dla operacji wyszukiwania NotFoundError I tak dalej.

nasze błędy powinny obsługiwać podstawowe właściwości błędów, takie jak message, nameI, najlepiej, stack. Ale mogą mieć również inne własne właściwości, np., HttpError obiekty mogą miećstatusCode właściwość o wartości takiej jak404 lub403 lub500.

JavaScript pozwala używać throw z dowolnym argumentem, więc technicznie nasze niestandardowe klasy błędów nie muszą dziedziczyć z Error. Ale jeśli dziedziczymy, wtedy można użyć obj instanceof Error do identyfikacji obiektów błędu. Więc lepiej dziedziczyć po nim.

wraz z rozwojem aplikacji, nasze własne błędy naturalnie tworzą hierarchię., Na przykład HttpTimeoutError może dziedziczyć z HttpError I tak dalej.

błąd rozszerzenia

jako przykład rozważmy funkcjęreadUser(json), która powinna odczytać JSON z danymi użytkownika.

oto przykład, jak poprawny json może wyglądać:

let json = `{ "name": "John", "age": 30 }`;

wewnętrznie użyjemyJSON.parse. Jeśli otrzyma zniekształcony json, to rzuca SyntaxError., Ale nawet jeśli json jest poprawny składniowo, to nie znaczy, że jest prawidłowym użytkownikiem, prawda? Może zabraknąć niezbędnych danych. Na przykład, może nie mieć name I age właściwości, które są niezbędne dla naszych użytkowników.

Nasza funkcjareadUser(json) nie tylko odczyta JSON, ale sprawdza („validate”) dane. Jeśli nie ma wymaganych pól lub format jest nieprawidłowy, oznacza to błąd. I to nie jest SyntaxError , ponieważ dane są poprawne składniowo, ale inny rodzaj błędu., Nazwiemy go ValidationError I utworzymy dla niego klasę. Błąd tego rodzaju powinien również zawierać informacje o polu obrażenia.

nasza ValidationError klasa powinna dziedziczyć z wbudowanej klasy Error.

Ta klasa jest wbudowana, ale oto jej przybliżony kod, więc możemy zrozumieć, co rozszerzamy:

teraz dziedziczmy z niej ValidationError I wypróbujmy ją w akcji:

uwaga: w linii (1) wywołujemy konstruktor nadrzędny., JavaScript wymaga od nas wywołania super w konstruktorze potomnym, więc jest to obowiązkowe. Konstruktor nadrzędny ustawia właściwość message.

konstruktor nadrzędny ustawia również właściwośćname na"Error", więc w linii(2) resetujemy ją do odpowiedniej wartości.,

spróbujmy użyć go w readUser(json):

try..catch blok w powyższym kodzie obsługuje zarówno nasz ValidationError, jak i wbudowany SyntaxError z JSON.parse.

proszę spojrzeć na to, jak używamyinstanceof, aby sprawdzić konkretny typ błędu w linii(*).,

możemy również spojrzeć na err.name, w ten sposób:

// ...// instead of (err instanceof SyntaxError)} else if (err.name == "SyntaxError") { // (*)// ...

wersjainstanceofjest znacznie lepsza, ponieważ w przyszłości zamierzamy rozszerzyćValidationError, tworzyć jego podtypy, takie jakPropertyRequiredError. Iinstanceofsprawdzenie będzie nadal działać dla nowych klas dziedziczących. Więc to jest przyszłościowe.

ważne jest również to, że jeśli catch spotka nieznany błąd, to zostanie on umieszczony w linii (**)., Blok catch wie tylko, jak obsłużyć błędy walidacji i składni, inne rodzaje (z powodu literówki w kodzie lub innych nieznanych) powinny wpaść.

dalsze dziedziczenie

KlasaValidationError jest bardzo ogólna. Wiele rzeczy może pójść nie tak. Właściwość może być nieobecna lub może być w złym formacie (np. wartość łańcuchowa dla age). Zróbmy bardziej konkretną klasę PropertyRequiredError, dokładnie dla nieobecnych właściwości. Będzie zawierać dodatkowe informacje o zaginionej nieruchomości.,

nowa klasa PropertyRequiredError jest łatwa w użyciu: wystarczy podać nazwę właściwości: new PropertyRequiredError(property). message jest generowany przez konstruktor.

należy pamiętać, żethis.name wPropertyRequiredError konstruktor jest ponownie przypisany ręcznie. Może to być nieco uciążliwe – przypisanie this.name = <class name> w każdej niestandardowej klasie błędów. Możemy tego uniknąć, tworząc własną klasę „basic error”, która przypisuje this.name = this.constructor.name. A potem odziedzicz z niego wszystkie nasze niestandardowe błędy.,

nazwijmy toMyError.

oto kod zMyErrorI inne niestandardowe klasy błędów, uproszczone:

teraz niestandardowe błędy są znacznie krótsze, zwłaszczaValidationError, ponieważ pozbyliśmy się linii"this.name = ..." w konstruktorze.

owijanie WYJĄTKÓW

celem funkcjireadUser w powyższym kodzie jest „odczytanie danych użytkownika”. W procesie mogą wystąpić różnego rodzaju błędy., Obecnie mamySyntaxError IValidationError, ale w przyszłościreadUser funkcja może rosnąć i prawdopodobnie generować inne rodzaje błędów.

kod wywołującyreadUser powinien obsłużyć te błędy. Obecnie używa wieluifs w blokucatch, które sprawdzają klasę i obsługują znane błędy oraz sprawdzają nieznane.

schemat wygląda tak:

w powyższym kodzie widzimy dwa rodzaje błędów, ale może ich być więcej.,

Jeśli funkcjareadUser generuje kilka rodzajów błędów, powinniśmy zadać sobie pytanie: czy naprawdę chcemy sprawdzać wszystkie typy błędów jeden po drugim za każdym razem?

często odpowiedź brzmi „nie”: chcielibyśmy być „o jeden poziom ponad wszystko”. Chcemy tylko wiedzieć, czy wystąpił „błąd odczytu danych” – dlaczego dokładnie tak się stało, jest często nieistotne (opisywany jest komunikat o błędzie). Albo, jeszcze lepiej, chcielibyśmy mieć sposób, aby uzyskać szczegóły błędu, ale tylko wtedy, gdy musimy.

technika, którą tutaj opisujemy nazywa się „owijanie WYJĄTKÓW”.,

  1. Stworzymy nową klasęReadError aby reprezentować ogólny błąd „odczytu danych”.
  2. funkcjareadUser wychwytuje błędy odczytu danych, które występują wewnątrz niej, takie jakValidationError ISyntaxError I generujeReadError.
  3. obiektReadError zachowa odniesienie do oryginalnego błędu w swojej właściwościcause.,

wtedy kod wywołujący readUserbędzie musiał tylko sprawdzić ReadError, a nie dla każdego rodzaju błędów odczytu danych. A jeśli potrzebuje więcej szczegółów błędu, może sprawdzić swoją właściwość cause.,

oto kod, który definiuje ReadError I demonstruje jego użycie w readUser I try..catch:

w powyższym kodzie readUser działa dokładnie tak, jak opisano – wyłapuje błędy składni i walidacji i zamiast tego wyrzuca ReadError (nieznane błędy są powtarzane jak zwykle).

więc Zewnętrzny kod sprawdza instanceof ReadError I tyle. Nie ma potrzeby wyświetlania wszystkich możliwych typów błędów.,

podejście nazywa się „zawijanie wyjątków”, ponieważ bierzemy wyjątki” niskiego poziomu ” i „zawijamy” je do ReadError, co jest bardziej abstrakcyjne. Jest szeroko stosowany w programowaniu obiektowym.

podsumowanie

  • możemy dziedziczyć zError I innych wbudowanych klas błędów normalnie. Musimy tylko zadbać o Właściwośćname I nie zapomnij zadzwonić super.
  • możemy użyć instanceof aby sprawdzić konkretne błędy. Działa również z dziedziczeniem., Ale czasami mamy obiekt błędu pochodzący z biblioteki innej firmy i nie ma łatwego sposobu, aby uzyskać jego klasę. Następnie można zastosować właściwość name do takich sprawdzeń.
  • owijanie wyjątków jest powszechną techniką: funkcja obsługuje wyjątki niskiego poziomu i tworzy błędy wyższego poziomu zamiast różnych błędów niskiego poziomu. Wyjątki niskiego poziomu czasami stają się właściwościami tego obiektu, takimi jak err.cause w powyższych przykładach, ale nie jest to ściśle wymagane.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *