Javascript er indbygget Error
giver nyttige oplysninger, men kan ofte føle sig manglende klarhed. En-størrelse-passer-alle er fantastisk til sproget, men vi kan gøre det bedre i vores egne apps. Det er her brugerdefinerede fejl kommer ind.
du har muligvis set brugerdefinerede fejl, når du bruger Node.js. Node er bygget i fejltyper som AssertionError
, RangeError
, ReferenceError
, SyntaxError
, og SystemError
er alle udvidelser af den indfødte Error
klasse.
brug af Error
som base giver dig al kraften i Javascript ‘ s implementering plus yderligere fordele. Her er blot nogle få:
- brugerdefinerede fejlmeddelelsesformater.
- yderligere egenskaber på Fejlobjektet.
- navngivne fejl for at gøre fejlfinding og betinget fejlhåndtering lettere.
- konsistente fejl for bibliotekets forbrugere at henvise til.
udvidelse af Fejlklassen
for at komme i gang, lad os bruge et generisk eksempel. Vi vil udvide Error
klassen og bruge super
til at arve dens funktioner.
class CustomError extends Error { constructor(...params) { super(...params) // We're spreading `params` as a way to bring all of `Error`'s functionality in. }}
nu, når du throw
en fejl, kan du gøre det med throw new CustomError("Something went wrong...")
. Det giver dig også mulighed for at kontrollere fejl mod typen:
try { throw new CustomError("Something went wrong")} catch (error) { if (error instance of CustomError) { // do something specifically for that type of error }}
dette alene gør ikke meget, bortset fra at give dig en ny fejltype at ringe og tjekke for. For bedre at forstå, hvad der kan gøres, lad os se på, hvad der kommer standard på Error
.
- Error.name
- Fejl.meddelelse
- fejl.prototype.toString ()
- fejl.prototype.konstruktør()
ikke meget at arbejde med er der? Bortset fra konstruktøren og toString
– metoden er navnet på fejlen og meddelelsen, der beskriver fejlen, de eneste dele, som vi sandsynligvis vil bruge. I eksemplet ovenfor er message
indstillet ved at passere” noget gik galt ” som argumentet ved instantiering af fejlen.
heldigvis er de fleste javascript-platforme som bro.ser og Node.js har tilføjet deres egne metoder og egenskaber oven på dem, der er anført. Vi vil fokusere på et par aspekter af Fejlimplementeringen fra V8, Javascript-motoren, der driver Chrome og Node.js.
de to interesseområder er stack
og captureStackTrace
. Som deres navne antyder, de giver dig mulighed for at overflade stakken spor. Lad os se, hvordan det ser ud med et eksempel.
class CustomError extends Error { constructor(...args) { super(...args) if (Error.captureStackTrace) { Error.captureStackTrace(this, CustomError) } this.name = "Our Custom Error" }}try { throw new CustomError("Something went wrong")} catch (err) { console.error(err.stack)}
i dette eksempel kalder vi Error.captureStackTrace
, hvis platformen understøtter det, for at sikre, at der tilføjes et komplet spor til vores brugerdefinerede fejl. Vi så throw
fejlen fra try
blokken, som vil passere kontrol til catch
blokken.
hvis du kører koden ovenfor, vil du se, at den første linje i stack
er fejlen name
og message
.
Our Custom Error: Something went wrong
denne fejl er ikke særlig “dyb”, så stakken er for det meste Node.JS internals. Hver linje er en” ramme ” af stakken. De indeholder detaljer om placeringen af fejlen i kodebasen.
nu hvor vi ved, hvordan vi laver og kalder en brugerdefineret fejl, lad os gøre det nyttigt.
tilpasning af Fejlindhold
den brugerdefinerede fejl, vi har arbejdet med, er fint, men lad os ændre det for at gøre det mere nyttigt. Klassen vil være CircuitError
. Vi bruger det til at levere brugerdefinerede fejl, der kommer fra en afbryder. Hvis du ikke er bekendt med mønsteret, er det okay. Implementeringsoplysningerne for afbryderen er ikke vigtige. Det vigtige er, at vi kan videregive nogle oplysninger til fejlen, og det vil præsentere disse oplysninger for brugeren.
en breaker har en “åben” tilstand, der ikke tillader noget at passere igennem det i et fast tidsrum. Lad os indstille vores CircuitError
op til at indeholde nogle detaljer, der kan være nyttige for de funktioner, der modtager det, når staten er OPEN
.
class CircuitError extends Error { // 1 constructor(state, nextAttempt, ...params) { super(...params) if (Error.captureStackTrace) { Error.captureStackTrace(this, CircuitError) } this.name = "CircuitError" this.state = state // 2 this.message = `The Circuit is ${state}.` // 3 if (nextAttempt) { this.timestamp = Date.now() this.nextAttempt = nextAttempt this.message += ` Next attempt can be made in ${this.nextAttempt - this.timestamp}ms.` } }}
vores opdaterede fejl gør et par nye ting, alt sammen inden for konstruktøren. Argumenterne bestået har ændret (1) til at omfatte state
af afbryderen, samt en nextAttempt
tidsstempel for at angive, hvornår afbryderen vil begynde at prøve anmodninger igen.
det indstiller derefter et par nye egenskaber og opdaterer meddelelsen afhængigt af de præsenterede værdier. Vi kan teste det ved at kaste en ny version af denne fejl.
try { throw new CircuitError("OPEN", Date.now() + 8000)} catch (err) { console.error(err)}
nu når vi kaster fejlen, tager den staten som det første argument og et tidsstempel som det andet. Til denne demo passerer vi 8000 millisekunder i fremtiden. Bemærk, at vi også logger fejlen selv, snarere end blot stakken.
kørsel af koden vil resultere i noget som følgende:
CircuitError : The Circuit is OPEN. Next attempt can be made in 6000ms. at Object.<anonymous> (/example.js:21:9) at Module._compile (internal/modules/cjs/loader.js:1063:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:1103:10) at Module.load (internal/modules/cjs/loader.js:914:32) at Function.Module._load (internal/modules/cjs/loader.js:822:14) at Function.Module.runMain (internal/modules/cjs/loader.js:1143:12) at internal/main/run_main_module.js:16:11 { name: 'Circuit Error', state: 'OPEN', message: 'The Circuit is OPEN. Next attempt can be made in 6000ms.', timestamp: 1580242308919, nextAttempt: 1580242314919}
resultatet er fejlnavnet efterfulgt af meddelelsen på første linje. Så har vi resten af stakken, efterfulgt af alle de egenskaber, vi har angivet i CircuitError
. Vores forbrugere af denne fejl kunne bruge disse data til at reagere på fejlen. For eksempel:
try { throw new CircuitError("OPEN", Date.now() + 8000)} catch (err) { customLogger(err) if (err.state === "OPEN") { handleOpenState(err.nextAttempt) }}
i stedet for en generisk fejl har vi nu noget, der passer bedre til vores applikations behov.
reaktion på fejl
brugerdefinerede fejl er en fantastisk måde at reagere på fejl. Det er almindeligt at antage, at alle fejl er uventede, men ved at give nyttige fejl kan du gøre deres eksistens lettere at håndtere. Ved at gøre brug af brugerdefinerede fejl kan vi ikke kun give brugere af vores applikationer værdifulde data, men vi præsenterer også muligheden for at reagere på fejltyper gennem instance of
– tilstanden.
hos Bearer bruger vi brugerdefinerede fejl til at standardisere svar i vores kode, give lige de oplysninger, du har brug for i vores klient, og gøre vores fejl Handlingsrettede.
Hvordan bruger du brugerdefinerede fejl i dine applikationer? Slut med os @BearerSH og lad os vide.