Erori personalizate, Extinderea erorii

Când dezvoltăm ceva, avem adesea nevoie de propriile noastre clase de erori pentru a reflecta lucruri specifice care pot merge prost în sarcinile noastre. Pentru erorile din operațiunile de rețea, este posibil să avem nevoie de HttpError, pentru operațiunile bazei de date , pentru operațiuni de căutare NotFoundError etc.

Erorile noastre trebuie să susțină proprietățile de eroare de bază, cum ar fi message, name și, de preferință, stack. Dar ei pot avea, de asemenea, alte proprietăți proprii, de exemplu, obiecte HttpError poate avea o proprietate statusCode cu o valoare ca sau 403.

JavaScript vă permite să utilizați throw Cu orice argument, așa că, din punct de vedere tehnic, clasele noastre de eroare personalizate nu trebuie să moștenească de la Error. Dar dacă moștenim, atunci este posibil să folosiți obj instanceof Error pentru a identifica eroarea obiectelor. Atunci este mai bine să moștenească de la el.

Pe măsură ce aplicația crește, greșelile noastre formează în mod natural o ierarhie. De exemplu, HttpTimeoutError poate moșteni de la HttpError și așa mai departe.

Eroare extinsă

De exemplu, luați în considerare o funcție care ar trebui să citească JSON cu datele utilizatorului.

aici este un exemplu de cum poate fi un valid:

iv id =” 70d48c33b0 „

Pe plan intern, vom folosi JSON.parse. Dacă primiți Format prost, apoi Shed SyntaxError. Dar chiar dacă este corect sintactic, care nu înseamnă că este un utilizator valabil, nu? Puteți pierde datele necesare. De exemplu, este posibil să nu aveți proprietăți de nume și vârstă care sunt esențiale pentru utilizatorii noștri.

Funcția noastră Nu numai că va citi JSON, ci va verifica (” Validați „) Datele. Dacă nu există câmpuri obligatorii sau formatul este incorect, atunci este o eroare. Și aceasta nu este o” sintaxă „, deoarece datele sunt corecte din punct de vedere sincronic, dar un alt tip de eroare. O vom numi iv id = „ca4dc42d43” și creați o clasă pentru el. O eroare de acest tip ar trebui, de asemenea, să aducă informațiile despre câmpul mineral.

Clasa noastră ValidationError ar trebui să moștenească din clasa încorporată Error.

Acest tip este încorporat, dar aici este codul dvs. aproximativ, astfel încât să putem înțelege ce ne extindem:

// El "pseudocódigo" para la clase Error incorporada definida por el propio JavaScriptclass Error { constructor(message) { this.message = message; this.name = "Error"; // (diferentes nombres para diferentes clases error incorporadas) this.stack = <call stack>; // no estándar, pero la mayoría de los entornos lo admiten }}

div id = „

NOTĂ: Pe linia(1)Noi numim Builder Tatăl. JavaScript cere ca noi să numimsuperîn constructorul fiului, deci este obligatoriu. Builderul părinte stabilește proprietateamessage.

Constructorul principal stabilește, de asemenea, proprietatea name în "Error", așa că pe linia (2) resetați-l la valoarea corectă.

Încercați să îl utilizați în

blocul try..catch în codul precedent se ocupă atât ValidationError ca SyntaxError Built-in iv id = „26e9776469” .

Notă Cum folosim instanceof pentru a verifica tipul de eroare specifică pe (*).

Am putea să ne uităm și la err.name, astfel:

// ...// en lugar de (err instanceof SyntaxError)} else if (err.name == "SyntaxError") { // (*)// ...

div id = „4B7EA79B7A” este mult mai bun, pentru că în Viitorul pe care îl vom extinde , vom face subtipuri de ea, caPropertyRequiredError. Și controlulinstanceofva continua să lucreze pentru clase noi moștenite. Apoi merge la viitor.

Este, de asemenea, important ca dacă catch găsiți o eroare necunoscută, apoi o re-aruncați pe linia (**). Blocul catch știu doar cum să gestioneze erorile de validare și sintaxă, alte tipuri (datorită unei erori tipografice în cod sau alți străini) trebuie să eșueze.

suplimentar moștenire

clasa ValidationError este foarte generic. Multe lucruri pot merge prost.Proprietatea poate fi absentă sau poate fi într-un format incorect (ca valoare de șir pentru age). Să facem o clasă mai concretă PropertyRequiredError, exact pentru proprietăți absente. Va lua informații suplimentare despre proprietatea lipsă.

class ValidationError extends Error { constructor(message) { super(message); this.name = "ValidationError"; }}class PropertyRequiredError extends ValidationError { constructor(property) { super("Sin propiedad: " + property); this.name = "PropertyRequiredError"; this.property = property; }}// Usofunction readUser(json) { let user = JSON.parse(json); if (!user.age) { throw new PropertyRequiredError("age"); } if (!user.name) { throw new PropertyRequiredError("name"); } return user;}// Ejemplo de trabajo con try..catchtry { let user = readUser('{ "age": 25 }');} catch (err) { if (err instanceof ValidationError) { alert("Dato inválido: " + err.message); // Dato inválido: Sin propiedad: name alert(err.name); // PropertyRequiredError alert(err.property); // name } else if (err instanceof SyntaxError) { alert("Error de sintaxis JSON: " + err.message); } else { throw err; // error desconocido, vuelva a lanzarlo }}

noua clasă PropertyRequiredError este ușor de utilizat: trebuie doar să trecem numele proprietății: new PropertyRequiredError(property) . message Citirea umană este generată de constructor.

Vă rugăm să rețineți că this.name în constructor PropertyRequiredError este atribuit din nou manual. Acest lucru poate deveni un pic plictisitor: atribuiți this.name = <class name> în fiecare clasă de eroare personalizată. Putem evita acest lucru făcând propria noastră clasă „eroare de bază” care atribuie iv id = „6f3d3c8379”

. Și apoi moșteniți toate erorile personalizate.

Să-l numim MyError.

aici este codul cu MyError și alte clase personalizate, eroare simplificată:

div id = „

„Ca4dc42D43” „> , deoarece ștergem linia iv id =” 28FE748D12 ” în constructor.

Îmbogățit de excepții

scopul scopului a funcției readUser în codul anterior este „Citiți datele utilizatorului”. Pot exista diferite tipuri de erori în acest proces. În acest moment avem SyntaxError și ValidationError, dar în viitor funcția readUser poate Creșteți și probabil generați alte tipuri de erori.

Codul care solicită readUser trebuie să gestioneze aceste erori. În acest moment, utilizează mai multe if în blocul catch, care verifică erorile cunoscute și aruncați din nou străinii din nou. /p>

schema este ca aceasta:

În codul precedent putem vedea două tipuri de erori, dar pot exista mai multe.

Dacă funcția readUser generează diferite tipuri de erori, atunci trebuie Întrebați-vă: Chiar dorim să verificăm toate tipurile de eroare unul câte unul de fiecare dată?

Adesea, răspunsul este „nu”: am dori să fim „un nivel mai presus de toate acestea”. Doar dorim să știm dacă există o „eroare de citire a datelor”: de ce sa întâmplat exact este adesea irelevant (mesajul de eroare îl descrie). Sau, mai bine, am dori să avem o modalitate de a obține detaliile erorii, dar numai dacă este necesar.

Tehnica pe care am descris-o aici se numește „excepții de ambalare”.

  1. Vom crea o nouă clasă IV id = „F7F64813A6” pentru a reprezenta o eroare generică a „citirii datelor”.
  2. Funcția readUser va detecta erorile de citire a datelor care apar în interiorul acesteia, ca ValidationError și SyntaxError și generarea unui F7F64813A6″> în schimb.
  3. Obiectul ReadError va menține referința de eroare originală pe proprietatea dvs. cause.

Apoi, codul care solicită readUser va trebui doar să verifice ReadError, nu toate tipurile de erori de citire d Atos Și dacă aveți nevoie de mai multe detalii despre o eroare, puteți verifica proprietatea cause.

aici este codul care definește iv Id = „F7F64813A6” și demonstrează utilizarea sa în readUser și try..catch:

class ReadError extends Error { constructor(message, cause) { super(message); this.cause = cause; this.name = 'ReadError'; }}class ValidationError extends Error { /*...*/ }class PropertyRequiredError extends ValidationError { /* ... */ }function validateUser(user) { if (!user.age) { throw new PropertyRequiredError("age"); } if (!user.name) { throw new PropertyRequiredError("name"); }}function readUser(json) { let user; try { user = JSON.parse(json); } catch (err) { if (err instanceof SyntaxError) { throw new ReadError("Error de sintaxis", err); } else { throw err; } } try { validateUser(user); } catch (err) { if (err instanceof ValidationError) { throw new ReadError("Error de validación", err); } else { throw err; } }}try { readUser('{json malo}');} catch (e) { if (e instanceof ReadError) { alert(e); // Error original: SyntaxError: inesperado token b en JSON en la posición 1 alert("Error original: " + e.cause); } else { throw e; }}

exact așa cum descrie SE SE: detectează erorile de sintaxă și validare și aruncă erorileReadError(erori necunoscute sunt generate ca de obicei).

Apoi, codul extern verifică instanceof ReadError și asta este. Nu este necesar să se menționeze toate tipurile de erori posibile.

Focusul este numit „Excepții de ambalare”, deoarece luăm excepții „nivel scăzut” și „ajustați” în ReadError care este mai abstract. Este utilizat pe scară largă în programarea orientată pe obiecte.

Rezumat

  • Putem moșteni de la Error și alte clase de erori încorporate. Trebuie doar să avem grijă de proprietatea name și nu uitați să apelați super.
  • Putem folosi instanceof pentru a verifica anumite erori. De asemenea, funcționează cu moștenire.Dar, uneori, avem un obiect de eroare care provine dintr-o bibliotecă terță parte și nu există o modalitate ușoară de a obține clasa sa. Apoi, proprietatea poate fi utilizat pentru astfel de controale.
  • Excepții Pachetul este o tehnică generalizată: o funcție se ocupă de excepții la nivel scăzut și creează erori la nivel înalt Locul mai multor erori de nivel scăzut. Excepții la nivel scăzut sunt uneori convertite în proprietăți ale acelui obiect ca err.cause în exemplele anterioare, dar care nu este strict necesar.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *