Når vi udvikler noget, har vi ofte brug for vores egne fejlklasser for at afspejle specifikke ting, der kan gå galt i vores opgaver. For fejl i netværksoperationer har vi muligvis brug for HttpError
, til databaseoperationer DbError
, til søgning af operationer NotFoundError
og så videre.
Vores fejl bør støtte grundlæggende fejl egenskaber som message
name
og, helst, stack
. Men de kan også have andre egenskaber af deres egne, f,, HttpError
objekter kan have en statusCode
ejendom med en værdi som f.eks. 404
eller 403
eller 500
.
JavaScript tillader at bruge throw
med noget argument, så teknisk set behøver vores brugerdefinerede fejlklasser ikke at arve fra Error
. Men hvis vi arver, bliver det muligt at bruge obj instanceof Error
til at identificere fejlobjekter. Så det er bedre at arve fra det.
efterhånden som applikationen vokser, danner vores egne fejl naturligvis et hierarki., For eksempel kan HttpTimeoutError
arve fra HttpError
og så videre.
Udvidelsesfejl
lad os som eksempel overveje en funktion readUser(json)
, der skal læse JSON med brugerdata.
Her er et eksempel på, hvordan et gyldigt json
kan se:
let json = `{ "name": "John", "age": 30 }`;
Internt, vil vi bruge JSON.parse
. Hvis den modtager misdannet json
, kaster den SyntaxError
., Men selvom json
er syntaktisk korrekt, betyder det ikke, at det er en gyldig bruger, ikke? Det kan gå glip af de nødvendige data. For eksempel, kan det ikke have name
og age
egenskaber, der er afgørende for vores brugere.
vores funktion readUser(json)
vil ikke kun læse JSON, men kontrollere (“validere”) dataene. Hvis der ikke er nogen obligatoriske felter, eller formatet er forkert, så er det en fejl. Og det er ikke en SyntaxError
, fordi dataene er syntaktisk korrekte, men en anden slags fejl., Vi kalder det ValidationError
og oprette en klasse for det. En sådan fejl bør også indeholde oplysninger om det krænkende felt.
voresValidationError
klasse skal arve fra den indbyggede Error
klasse.
Denne klasse er indbygget, men her er dens omtrentlige kode, så vi kan forstå, hvad vi har at udvide:
lad os Nu arver ValidationError
fra det, og prøve det i praksis:
bemærk: i linje (1)
vi kalde den forælder constructor., JavaScript kræver, at vi ringer super
i børnekonstruktøren, så det er obligatorisk. Den overordnede konstruktør indstillermessage
ejendom.
forældrekonstruktøren indstiller ogsåname
egenskaben til"Error"
, så i linjen(2)
nulstiller vi den til den rigtige værdi.,
Lad os prøve at bruge det i readUser(json)
:
try..catch
blok i koden ovenfor håndterer både vores ValidationError
og den indbyggede SyntaxError
fra JSON.parse
.
Tag et kig på, hvordan vi bruger instanceof
for at kontrollere for den specifikke fejltype i linjen (*)
.,
Vi kunne også se på err.name
, som dette:
// ...// instead of (err instanceof SyntaxError)} else if (err.name == "SyntaxError") { // (*)// ...
instanceof
version er meget bedre, fordi vi i fremtiden kommer til at udvide ValidationError
, gøre undertyper af det, f.eks. PropertyRequiredError
. Og instanceof
check vil fortsætte med at arbejde for nye arvende klasser. Så det er fremtidssikret.
det er også vigtigt, at hvis catch
opfylder en ukendt fejl, så genovervejer den den i linjen (**)
., catch
block ved kun, hvordan man håndterer validerings-og syntaksfejl, andre typer (på grund af en skrivefejl i koden eller andre ukendte) skal falde igennem.
yderligere arv
ValidationError
klassen er meget generisk. Mange ting kan gå galt. Ejendommen kan være fraværende, eller den kan være i et forkert format (som en strengværdi for age
). Lad os lave en mere konkret klasse PropertyRequiredError
, præcis for fraværende egenskaber. Det vil bære yderligere oplysninger om ejendommen, der mangler.,
den nye klasse PropertyRequiredError
er nem at bruge: vi behøver kun at passere egenskabsnavnet: new PropertyRequiredError(property)
. Den menneskelige læsbare message
genereres af konstruktøren.
Bemærk, atthis.name
iPropertyRequiredError
constructor igen tildeles manuelt. Det kan blive lidt kedeligt – at tildele this.name = <class name>
i hver brugerdefineret fejlklasse. Vi kan undgå det ved at lave vores egen “grundlæggende fejl” klasse, der tildeler this.name = this.constructor.name
. Og så arve alle vores brugerdefinerede fejl fra det.,
lad os kalde det MyError
.
Her er koden med MyError
og andre brugerdefinerede fejl klasser, forenklet:
Nu brugerdefinerede fejl er meget kortere, især ValidationError
, som vi er sluppet af med de "this.name = ..."
linje i konstruktøren.
indpakning undtagelser
formålet med funktionen readUser
i koden ovenfor er “at læse brugerdata”. Der kan forekomme forskellige slags fejl i processen., Lige nu har vi SyntaxError
og ValidationError
, men i fremtiden readUser
funktion kan vokse og sandsynligvis generere andre typer af fejl.
koden, der kalderreadUser
, skal håndtere disse fejl. Lige nu bruger den flere if
s icatch
block, der kontrollerer klassen og håndterer kendte fejl og genkalder de ukendte.
ordningen er sådan:
i koden ovenfor kan vi se to typer fejl, men der kan være flere.,
hvis readUser
-funktionen genererer flere slags fejl, skal vi spørge os selv: vil vi virkelig kontrollere for alle fejltyper en efter en hver gang?
ofte er svaret “nej”: vi vil gerne være “et niveau frem for alt det”. Vi vil bare vide, om der var en “datalæsningsfejl” – hvorfor nøjagtigt det skete, er ofte irrelevant (fejlmeddelelsen beskriver det). Eller endnu bedre, vi vil gerne have en måde at få fejloplysningerne på, men kun hvis vi har brug for det.
teknikken, som vi beskriver her, kaldes “indpakningsundtagelser”.,
- Vi laver en ny klasse
ReadError
for at repræsentere en generisk “data læsning” fejl. - funktion
readUser
vil fange data læsning fejl, der opstår inde i det, som f.eks.ValidationError
ogSyntaxError
, og generere enReadError
i stedet for. -
ReadError
objekt vil holde henvisningen til den oprindelige fejl i sincause
ejendom.,
derefter skal koden, der kalder readUser
, kun kontrollere for ReadError
, ikke for alle slags datalæsningsfejl. Og hvis det har brug for flere detaljer om en fejl, kan den kontrollere dens cause
ejendom.,
Her er den kode, der definerer ReadError
og demonstrerer dens anvendelse i readUser
og try..catch
:
I koden ovenfor, readUser
fungerer præcis som beskrevet – fangster syntaks og validering fejl og kaster ReadError
fejl, i stedet for (ukendt fejl er rethrown som sædvanlig).
så den ydre kode kontrollerer instanceof ReadError
og det er det. Ingen grund til at liste alle mulige fejltyper.,
fremgangsmåden kaldes “indpakning undtagelser”, fordi vi tager “lavt niveau” undtagelser og “wraprap” dem iReadError
det er mere abstrakt. Det er meget udbredt i objektorienteret programmering.
resum and
- Vi kan arve fra
Error
og andre indbyggede fejlklasser normalt. Vi skal bare passe påname
ejendom og glem ikke at ringe tilsuper
. - Vi kan bruge
instanceof
til at kontrollere for bestemte fejl. Det virker også med arv., Men nogle gange har vi en fejl objekt, der kommer fra en 3.-parts bibliotek, og der er ingen nem måde at få sin klasse. Dereftername
ejendom kan bruges til sådanne kontroller. - indpakning af undtagelser er en udbredt teknik: en funktion håndterer undtagelser på lavt niveau og skaber fejl på højere niveau i stedet for forskellige lavt niveau. Undtagelser på lavt niveau bliver undertiden egenskaber for det objekt som
err.cause
i eksemplerne ovenfor, men det er ikke strengt nødvendigt.