Når vi utvikle noe, vi trenger ofte vår egen feil klasser for å reflektere spesifikke ting som kan gå galt i våre oppgaver. For feil i nettverket operasjoner vi kan trenge HttpError
, for database operasjoner DbError
, for å søke operasjoner NotFoundError
og så videre.
Vår feil bør støtte grunnleggende feil egenskaper som message
, name
og helst stack
. Men de kan også ha andre egenskaper av sine egne, f.eks., HttpError
objekter kan ha en statusCode
eiendom med en verdi som 404
eller 403
eller 500
.
JavaScript-gjør det mulig å bruke throw
med noe argument, så teknisk våre egne feil klasser trenger ikke å arve fra Error
. Men hvis vi arver, så det blir mulig å bruke obj instanceof Error
for å identifisere feil objekter. Så det er bedre å arve fra det.
Som programmet vokser, våre egne feil naturlig form av et hierarki., For eksempel HttpTimeoutError
kan arve fra HttpError
, og så videre.
Utvide Feil
Som et eksempel, la oss vurdere en funksjon readUser(json)
som bør lese JSON med brukerdata.
Her er et eksempel på hvordan en gyldig json
kan se ut:
– >
let json = `{ "name": "John", "age": 30 }`;
Internt, vil vi bruke JSON.parse
. Hvis den mottar ugyldig json
, så det kaster SyntaxError
., Men selv om json
er syntaktisk korrekt, det betyr ikke at det er en gyldig bruker, ikke sant? Det kan gå glipp av nødvendig data. For eksempel kan det ikke har name
og age
egenskaper som er viktige for våre brukere.
Vår funksjon readUser(json)
vil ikke bare lese JSON, men sjekk («validere») av data. Hvis det ikke er noen nødvendige felt, eller formatet er feil, så er det en feil. Og det er ikke en SyntaxError
, fordi dataene er syntaktisk korrekt, men en annen type feil., Vi kaller det ValidationError
og opprette en klasse for det. En feil av denne type bør også bære informasjon om kriminalitetsforebyggende feltet.
Vår ValidationError
klassen bør arv fra den innebygde Error
klasse.
klassen er innebygd, men her er omtrentlig kode, slik at vi kan forstå hva vi strekker seg:
la oss Nå arve ValidationError
og prøv det i aksjon:
merk: på linje (1)
vi kaller den overordnede constructor., JavaScript krever oss til å kalle super
i barnet konstruktør, så det er obligatorisk. Den overordnede konstruktøren setter message
eiendom.
Den overordnede constructor angir også name
eiendom til "Error"
, så i linjen (2)
vi tilbakestille den til den riktige verdien.,
La oss prøve å bruke det i readUser(json)
:
try..catch
blokker i koden ovenfor håndterer både vår ValidationError
og den innebygde SyntaxError
fra JSON.parse
.
ta en titt på hvordan vi bruker instanceof
for å sjekke om feilen skriv linjen (*)
.,
Vi kan også se på err.name
, som dette:
– >
// ...// instead of (err instanceof SyntaxError)} else if (err.name == "SyntaxError") { // (*)// ...
instanceof
versjonen er mye bedre, fordi vi i fremtiden kommer til å utvide ValidationError
, lage undergrupper av det, som PropertyRequiredError
. Og instanceof
sjekk vil fortsette å arbeide for nye klasser som arver. Så det er fremtiden.
det er Også viktig at hvis catch
møter en ukjent feil, så er det rethrows det i linje (**)
., catch
blokkere bare vet hvordan man skal håndtere validering og syntaks feil, andre typer (på grunn av en skrivefeil i koden eller annen ukjent ones), skal falle gjennom.
Videre arv
ValidationError
klassen er veldig generell. Mange ting kan gå galt. Holderen kan være fraværende eller det kan være i feil format (som en string verdi for age
). La oss gjøre en mer konkret klasse PropertyRequiredError
, nøyaktig for fraværende egenskaper. Det vil bære mer informasjon om eiendommen som mangler.,
Den nye klassen PropertyRequiredError
er enkel å bruke:) vi trenger bare å passere den egenskapen navn: new PropertyRequiredError(property)
. Den lesbar message
er generert av konstruktøren.
Vær oppmerksom på at this.name
i PropertyRequiredError
constructor er igjen tilordnes manuelt. Det kan bli litt kjedelig – for å tilordne this.name = <class name>
i hver egendefinerte feil klasse. Vi kan unngå det ved å lage vår egen «grunnleggende feil» klasse som tildeler this.name = this.constructor.name
. Og så arver alle våre egne feil fra det.,
La oss kalle det MyError
.
Her er koden med MyError
og andre tilpassede feil klasser, forenklet:
Nå tilpasset feil er mye kortere, spesielt ValidationError
, som vi ble kvitt "this.name = ..."
line i konstruktøren.
Innpakning unntak
formålet med funksjonen readUser
i koden ovenfor er «å lese brukerdata». Det kan oppstå forskjellige typer feil i prosessen., Akkurat nå har vi SyntaxError
og ValidationError
, men i framtiden. readUser
funksjon kan vokse og sannsynligvis generere flere typer feil.
koden som kaller readUser
skal håndtere disse feilene. Akkurat nå er det bruker flere if
s i catch
blokker, som sjekker klasse og håndtere kjente feil og rethrow det ukjente seg.
ordningen er som dette:
I koden ovenfor kan vi se to typer feil, men det kan være mer.,
Hvis readUser
funksjonen genererer flere typer feil, da bør vi spørre oss selv: har vi virkelig ønsker å sjekke om alle feil typer en-av-en hver tid?
Ofte svaret er «Nei»: vi ønsker å være «ett nivå over alle som». Vi vil bare vite om det var en «data lesing feil» – hvorfor akkurat det som skjedde er ofte irrelevant (de feilmelding beskriver det). Eller, enda bedre, vi ønsker å ha en måte å få feil informasjon, men bare hvis vi trenger det.
Den teknikk som vi beskriver her kalles «innpakning unntak».,
- Vi vil lage en ny klasse
ReadError
for å representere en generisk «data leser» feil. - funksjon
readUser
vil fange data leser feil som oppstår i den, for eksempelValidationError
ogSyntaxError
, og generere enReadError
i stedet. -
ReadError
objektet vil holde referanse til den opprinnelige feilen i sincause
eiendom.,
Så koden som kaller readUser
vil bare trenger å se etter ReadError
, ikke for hver type data du leser feil. Og hvis det er behov for mer detaljer om feil, det kan du kontrollere cause
eiendom.,
Her er koden som definerer ReadError
og viser sin bruk i readUser
og try..catch
:
I koden ovenfor, readUser
fungerer nøyaktig som beskrevet – fangst syntaks og validering feil og kaster ReadError
feil i stedet (ukjent feil er rethrown som vanlig).
Slik at den ytre kontrollerer koden instanceof ReadError
og det er det. Ingen trenger å liste opp alle mulige typer feil.,
tilnærmingen kalles «innpakning unntak», fordi vi ta «lavt nivå» unntak og «pakk» dem til ReadError
som er mer abstrakt. Det er mye brukt i objekt-orientert programmering.
Oppsummering
- Vi kan arve fra
Error
og andre innebygde feil klasser normalt. Vi trenger bare å ta vare påname
eiendom og ikke glem å ringesuper
. - kan Vi bruke
instanceof
for å se etter bestemt feil. Det fungerer også med arv., Men noen ganger har vi en feil objekt som kommer fra en 3. parts bibliotek, og det er ingen enkel måte å få sin klasse. Derettername
eiendom kan bli brukt for slike sjekker. - Innpakning unntak er en utbredt teknikk: en funksjon håndterer lavt nivå unntak og skaper høyere nivå av feil i stedet for ulike lavt nivå de. Lavt nivå unntak noen ganger bli egenskaper av at objektet som
err.cause
i eksemplene ovenfor, men det er ikke strengt nødvendig.