Když něco vyvíjíme, často potřebujeme vlastní chybové třídy, aby odrážely konkrétní věci, které se mohou v našich úkolech pokazit. Za chyby v provozu sítě můžeme třeba HttpError
, pro databázové operace DbError
, pro hledání operace NotFoundError
, a tak dále.
Naše chyby by měly podporovat základní chyba vlastnosti, jako je message
name
a, pokud možno, stack
. Mohou však mít i jiné vlastní vlastnosti, např., HttpError
objekty mohou mít statusCode
vlastnost s hodnotou, jako je 404
nebo 403
nebo 500
.
JavaScript umožňuje používatthrow
s jakýmkoli argumentem, takže technicky naše vlastní třídy chyb nemusí dědit zError
. Pokud však zdědíme, je možné použítobj instanceof Error
k identifikaci chybových objektů. Takže je lepší dědit z toho.
jak aplikace roste, naše vlastní chyby přirozeně tvoří hierarchii., Například HttpTimeoutError
může dědit z HttpError
a tak dále.
rozšíření chyby
jako příklad uvažujme funkci readUser(json)
, která by měla číst JSON s uživatelskými daty.
Tady je příklad toho, jak platné json
může vypadat:
let json = `{ "name": "John", "age": 30 }`;
Interně, budeme používat JSON.parse
. Pokud obdrží chybně json
, hodí SyntaxError
., Ale i když jejson
syntakticky správný, neznamená to, že je to platný uživatel, že? Může chybět potřebná data. Například, nemusí mít name
age
vlastnosti, které jsou nezbytné pro naše uživatele.
Naše funkce readUser(json)
budou nejen číst, JSON, ale kontrola („validovat“) data. Pokud nejsou požadovaná pole nebo formát je špatný, pak je to chyba. A to není SyntaxError
, protože data jsou syntakticky správná, ale jiný druh chyby., Nazveme to ValidationError
a vytvoříme pro ni třídu. Chyba tohoto druhu by také měla obsahovat informace o přestupkovém poli.
našeValidationError
třída by měla dědit z vestavěné třídy Error
.
ta třída je postavena-in, ale zde je jeho přibližná kód, takže můžeme pochopit, co jsme rozšíření:
Teď pojďme zdědit ValidationError
z toho a zkuste to v akci:
Prosím poznámka: v řádku (1)
nazýváme rodič konstruktor., JavaScript vyžaduje, abychom volali super
v dětském konstruktoru, takže je to povinné. Nadřazený Konstruktor nastaví vlastnost message
.
rodič konstruktor také nastaví name
vlastnost "Error"
, tak v řádku (2)
obnovit jej na správnou hodnotu.,
zkusme použít to v readUser(json)
:
try..catch
blok v kódu výše zpracovává obě naše ValidationError
a postaven-v SyntaxError
JSON.parse
.
podívejte se, jak používáme instanceof
pro kontrolu konkrétního typu chyby v řádku (*)
.,
Můžeme se také podívat na err.name
, například:
// ...// instead of (err instanceof SyntaxError)} else if (err.name == "SyntaxError") { // (*)// ...
instanceof
verze je mnohem lepší, protože v budoucnu budeme stále rozšiřovat ValidationError
, aby podtypy, jako je PropertyRequiredError
. Ainstanceof
kontrola bude i nadále pracovat pro nové dědické třídy. To je důkaz budoucnosti.
také je důležité, že pokud catch
splňuje neznámou chybu,přehodnotí ji v řádku (**)
., Blok catch
ví, jak zvládnout chyby validace a syntaxe, jiné druhy (kvůli překlepu v kódu nebo jiné neznámé) by měly propadnout.
další dědičnost
třídaValidationError
je velmi obecná. Mnoho věcí se může pokazit. Vlastnost může chybět nebo může být ve špatném formátu (jako hodnota řetězce pro age
). Udělejme konkrétnější třídu PropertyRequiredError
, přesně pro chybějící vlastnosti. Bude obsahovat další informace o majetku, který chybí.,
nová třída PropertyRequiredError
se snadno používá: stačí předat název vlastnosti: new PropertyRequiredError(property)
. Čitelný message
je generován konstruktorem.
Upozorňujeme, že this.name
v konstruktor je opět přiřazen ručně. To může být trochu únavné – přiřadit this.name = <class name>
v každé vlastní třídě chyb. Můžeme se tomu vyhnout tím, že uděláme vlastní třídu „základní chyby“, která přiřadí this.name = this.constructor.name
. A pak z toho zdědí všechny naše vlastní chyby.,
říkejme tomu MyError
.
Zde je kód MyError
a další vlastní chybovou tříd, zjednodušená:
Nyní vlastní chyby jsou mnohem kratší, zejména ValidationError
, jak jsme se zbavili "this.name = ..."
řádek v konstruktoru.
výjimky pro balení
účelem funkce readUser
ve výše uvedeném kódu je „Číst uživatelská data“. V procesu se mohou vyskytnout různé druhy chyb., Teď máme SyntaxError
ValidationError
, ale v budoucnu readUser
funkce může růst a pravděpodobně vytvářet jiné druhy chyb.
kód, který volá readUser
, by měl tyto chyby zpracovat. Teď to používá více if
catch
blok, podívejte se na třídy a zvládnout známé chyby a rethrow neznámé ty.
schéma je následující:
v kódu výše vidíme dva typy chyb, ale může jich být více.,
Pokud funkcereadUser
generuje několik druhů chyb, měli bychom se ptát sami sebe: opravdu chceme zkontrolovat všechny typy chyb jeden po druhém pokaždé?
často je odpověď „Ne“: chtěli bychom být „o jednu úroveň výše“. Chceme jen vědět, zda došlo k „chybě čtení dat“ – proč přesně se to stalo, je často irelevantní (chybová zpráva ji popisuje). Nebo ještě lépe, chtěli bychom mít způsob, jak získat podrobnosti o chybě, ale pouze v případě, že potřebujeme.
technika, kterou zde popisujeme, se nazývá „balicí výjimky“.,
- vytvoříme novou třídu
ReadError
představuje generický „čtení dat“ chyba. - funkce
readUser
bude chytat čtení dat chyby, které se vyskytují uvnitř, napříkladValidationError
SyntaxError
a generovatReadError
místo. -
ReadError
objekt ponechá odkaz na původní chybu ve své vlastnosticause
.,
Pak kód, který volá readUser
bude mít pouze zkontrolovat ReadError
, ne pro každý druh dat, chyby při čtení. A pokud potřebuje více podrobností o chybě,může zkontrolovat vlastnostcause
.,
Zde je kód, který definuje ReadError
a demonstruje jeho použití v readUser
try..catch
:
V kódu výše, readUser
funguje přesně tak, jak je popsáno úlovky syntaxe a chyby ověření a hody ReadError
chyby místo (neznámé chyby jsou rethrown jako obvykle).
takže vnější kód kontroluje instanceof ReadError
a to je vše. Není třeba uvádět všechny možné typy chyb.,
přístup se nazývá „balicí výjimky“, protože bereme výjimky“ nízké úrovně „a“ zabalíme“je do ReadError
to je abstraktnější. Je široce používán v objektově orientovaném programování.
shrnutí
- můžeme dědit z
Error
a dalších vestavěných chybových tříd normálně. Stačí se postarat o vlastnostname
a nezapomeňte zavolatsuper
. - můžeme použít
instanceof
pro kontrolu konkrétních chyb. Pracuje také s dědictvím., Ale někdy máme chybový objekt pocházející z knihovny 3. strany a není snadný způsob, jak získat jeho třídu. Pakname
vlastnost může být použita pro takové kontroly. - balení výjimek je rozšířená technika: funkce zpracovává výjimky nízké úrovně a vytváří chyby vyšší úrovně namísto různých nízkoúrovňových. Výjimky na nízké úrovni se někdy stávají vlastnostmi tohoto objektu, jako je
err.cause
ve výše uvedených příkladech, ale to není nezbytně nutné.