amikor valamit fejlesztünk, gyakran szükségünk van saját hibaosztályainkra, hogy tükrözze azokat a konkrét dolgokat, amelyek hibásak lehetnek a feladatainkban. A hálózati műveletek hibáihoz szükség lehet HttpError
adatbázisműveletekhez DbError
, a keresési műveletekhez NotFoundError
stb.
hibáinknak támogatniuk kell az olyan alapvető hibatulajdonságokat, mint a message
, name
és lehetőleg stack
. De lehetnek más saját tulajdonságaik is, például, HttpError
az objektumok statusCode
tulajdonsággal rendelkezhetnek, amelynek értéke 404
vagy 403
vagy 500
.
a JavaScript lehetővé teszi athrow
használatát bármilyen argumentummal, így technikailag az egyéni hibaosztályoknak nem kell örökölniük aError
– tól. De ha öröklünk, akkor lehetővé válik aobj instanceof Error
használata a hibaobjektumok azonosításához. Tehát jobb örökölni tőle.
ahogy az alkalmazás növekszik, saját hibáink természetesen hierarchiát alkotnak., Például a HttpTimeoutError
örökölhet a HttpError
stb.
kiterjesztési hiba
példaként tekintsünk egy readUser(json)
függvényt, amelynek a JSON-t a felhasználói adatokkal kell olvasnia.
Íme egy példa arra, hogy egy érvényesjson
hogyan nézhet ki:
let json = `{ "name": "John", "age": 30 }`;
belsőleg a JSON.parse
. Ha rosszul formázott json
, akkor SyntaxError
dob., De még akkor is, ha a json
szintaktikailag helyes, ez nem jelenti azt, hogy érvényes felhasználó, igaz? Lehet, hogy hiányzik a szükséges adatok. Előfordulhat például, hogy nem rendelkezik name
és age
olyan tulajdonságokkal, amelyek nélkülözhetetlenek a felhasználóink számára.
funkciónkreadUser(json)
nem csak a JSON-t olvassa, hanem ellenőrzi (“validálja”) az adatokat. Ha nincsenek kötelező mezők, vagy a formátum rossz, akkor ez hiba. Ez nem egy SyntaxError
, mert az adatok szintaktikailag helyesek, hanem egy másik hiba., Hívjuk ValidationError
– nak és hozzunk létre egy osztályt. Az ilyen jellegű hibának tartalmaznia kell a jogsértő mezőre vonatkozó információkat is.
ValidationError
osztály kell örökölni a beépítettError
osztály.
Ez az osztály beépített, de itt van a hozzávetőleges kódja, így megérthetjük, hogy mit bővítünk:
most örököljük ValidationError
tőle, és próbáljuk meg akcióban:
megjegyzés: a sorban (1)
hívjuk a szülő konstruktort., A JavaScript megköveteli, hogy a super
– ot hívjuk a gyermek konstruktorban, így ez kötelező. A szülő konstruktor beállítja amessage
tulajdonságot.
a szülő konstruktor is beállítja aname
tulajdonság"Error"
, így a sorban(2)
visszaállítjuk a megfelelő értékre.,
próbáljuk meg használni a readUser(json)
:
a try..catch
blokk a fenti kódban kezeli mind a ValidationError
, mind a beépített SyntaxError
>JSON.parse
.
kérjük, nézze meg, hogyan használjuk a instanceof
– ot, hogy ellenőrizzük a (*)
sor konkrét hibatípusát.,
Mi is nézd err.name
, mint ez:
// ...// instead of (err instanceof SyntaxError)} else if (err.name == "SyntaxError") { // (*)// ...
A instanceof
verzió sokkal jobb, mert a jövőben fogjuk kiterjeszteni ValidationError
, hogy altípusai, mint a PropertyRequiredError
. És instanceof
check továbbra is dolgozni fog az új öröklő osztályok. Tehát ez jövőbiztos.
szintén fontos, hogy ha catch
találkozik egy ismeretlen hibával, akkor újragondolja a (**)
sorban., Acatch
blokk csak az érvényesítési és szintaktikai hibákat tudja kezelni, más típusoknak (a kód elírása vagy más ismeretlen) át kell esniük.
további öröklés
aValidationError
osztály nagyon általános. Sok minden rosszra fordulhat. A tulajdonság hiányozhat, vagy rossz formátumban lehet (például a age
karakterlánc értéke). Készítsünk egy konkrétabb osztályt PropertyRequiredError
, pontosan a hiányzó tulajdonságok esetén. További információkat tartalmaz a hiányzó ingatlanról.,
az új osztályPropertyRequiredError
könnyen használható:csak a tulajdonság nevét kell átadnunk: new PropertyRequiredError(property)
. Az ember által olvasható message
generálja a kivitelező.
kérjük, vegye figyelembe, hogythis.name
inPropertyRequiredError
a konstruktort ismét manuálisan rendelik hozzá. Ez kissé unalmas lehet-hozzárendelni this.name = <class name>
minden egyéni hibaosztályban. Mi lehet elkerülni, hogy a saját “basic error” osztály, amely hozzárendeli this.name = this.constructor.name
. Aztán örököl minden egyéni hibát belőle.,
nevezzükMyError
.
itt van a kódMyError
és más egyéni hibaosztályok, egyszerűsített:
most egyéni hibák sokkal rövidebbek, különösen ValidationError
, ahogy megszabadultunk a"this.name = ..."
sor a kivitelező.
areadUser
funkció célja a “felhasználói adatok olvasása”. Különböző típusú hibák fordulhatnak elő a folyamatban., Jelenleg van SyntaxError
és ValidationError
, de a jövőben readUser
függvény nőhet, és valószínűleg más típusú hibákat generálhat.
areadUser
kódnak kell kezelnie ezeket a hibákat. Jelenleg több if
s-t használ a catch
blokkban, amelyek ellenőrzik az osztályt, kezelik az ismert hibákat, és újragondolják az ismeretleneket.
a séma így van:
a fenti kódban kétféle hibát látunk, de több is lehet.,
Ha a readUser
funkció többféle hibát generál, akkor fel kell tennünk magunknak a kérdést: valóban minden hibatípust egyenként szeretnénk ellenőrizni?
gyakran a válasz “nem”: szeretnénk”egy szint mindenek felett” lenni. Csak azt szeretnénk tudni, hogy volt – e “adatolvasási hiba” – miért történt pontosan ez gyakran irreleváns (a hibaüzenet leírja). Vagy, még jobb, szeretnénk, hogy egy módja annak, hogy a hiba részleteit, de csak akkor, ha kell.
az itt leírt technikát “csomagolás kivételeknek”nevezzük.,
- új osztályt készítünk
ReadError
általános” adatolvasási ” hiba megjelenítéséhez. - a
readUser
fogási adatok olvasási hibák fordulnak elő benne, mint például a ésSyntaxError
, és létrehoz egyReadError
. - a
ReadError
objektum megtartja az eredeti hibára való hivatkozást acause
tulajdonságában.,
ezután a readUser
hívó kódnak csak a ReadError
értéket kell ellenőriznie, nem minden adatolvasási hiba esetén. Ha pedig egy hiba további részleteire van szüksége, ellenőrizheti acause
tulajdonságát.,
itt van a ReadError
és a readUser
és try..catch
:
a fenti kódban readUser
pontosan a leírt módon működik – fogások szintaxis és validációs hibák és dob ReadError
hibák helyett (ismeretlen hibák újragondolják a szokásos módon).
tehát a külső kódinstanceof ReadError
és ennyi. Nem kell felsorolni az összes lehetséges hibatípust.,
a megközelítés az úgynevezett “csomagolás kivételek”, mert vesszük “alacsony szintű” kivételek”, és” wrap”őketReadError
ez több elvont. Széles körben használják az objektumorientált programozásban.
összefoglaló
- a
Error
és más beépített hibaosztályok általában örökölhetők. Csak gondoskodnunk kell aname
tulajdonságról, és ne felejtsük el felhívni asuper
– t. - a
instanceof
segítségével ellenőrizhetjük a konkrét hibákat. Az örökléssel is működik., De néha van egy hiba objektum jön egy 3rd-party könyvtár, és nincs könnyű módja annak, hogy az osztály. Ezután aname
tulajdonság használható ilyen ellenőrzésekhez. - a kivételek csomagolása széles körben elterjedt technika: a funkció alacsony szintű kivételeket kezel, és magasabb szintű hibákat hoz létre a különböző alacsony szintű hibák helyett. Az alacsony szintű kivételek néha az objektum tulajdonságává válnak, mint például a
err.cause
a fenti példákban, de ez nem feltétlenül szükséges.