Errori personalizzati, estendendo errore

Quando sviluppiamo qualcosa, abbiamo spesso bisogno delle nostre classi di errore per riflettere cose specifiche che possono sbagliare nei nostri compiti. Per gli errori nelle operazioni di rete, potremmo aver bisogno di HttpError, per le operazioni del database

, per le operazioni di ricerca NotFoundError, ecc.

I nostri errori devono supportare le proprietà di errore di base come message, name e, preferibilmente, stack. Ma possono anche avere altre proprietà proprie, ad esempio, oggetti HttpError potrebbe avere una proprietà statusCode con un valore come o 403 o 500.

JavaScript consente di utilizzare throw Con qualsiasi argomento, quindi tecnicamente le nostre classi di errore personalizzate non hanno bisogno di ereditare da Error. Ma se ereditiamo, allora è possibile utilizzare obj instanceof Error per identificare gli oggetti Errore. Quindi è meglio ereditare da lui.

Come cresce l’applicazione, i nostri errori formano naturalmente una gerarchia. Ad esempio, HttpTimeoutError può ereditare da HttpError, e così via.

Estensione dell’errore

Ad esempio, considera una funzione che dovrebbe leggere JSON con i dati dell’utente.

Ecco un esempio di come un Valido:

let json = `{ "name": "John", "age": 30 }`;

Internamente, useremo JSON.parse. Se si riceve scarsamente formato, quindi Shed SyntaxError. Ma anche se è sintatticamente corretto, ciò non significa che sia un utente valido, giusto? Puoi perdere i dati necessari. Ad esempio, potresti non avere nome e proprietà di età essenziali per i nostri utenti.

La nostra funzione readUser(json) non solo leggerà JSON, ma verificherà (” Convalidare “) i dati. Se non ci sono campi obbligatori o il formato non è corretto, è un errore. E non è un” sintaxError “, poiché i dati sono sintatticamente corretti, ma un altro tipo di errore. Lo chiameremo ValidationError e crea una classe per questo. Un errore di tale tipo dovrebbe anche portare le informazioni sul campo minerale.

la nostra classe ValidationError dovrebbe ereditare dalla classe integrata Error.

Il tipo è incorporato, ma qui è il tuo codice approssimativo in modo che possiamo capire cosa stiamo estendendo:

Id = “5e6e595144″>

ora INDIVIT ValidationError e dimostralo in azione:

class ValidationError extends Error { constructor(message) { super(message); // (1) this.name = "ValidationError"; // (2) }}function test() { throw new ValidationError("Vaya!");}try { test();} catch(err) { alert(err.message); // Vaya! alert(err.name); // ValidationError alert(err.stack); // una lista de llamadas anidadas con números de línea para cada una}

Nota: sulla linea (1) chiamiamo il padre costruttore. JavaScript richiede che chiamiamo super nel Builder Son, quindi è obbligatorio. Il genitore Builder imposta la proprietà message.

Il costruttore principale imposta anche la proprietà name in "Error", quindi sulla riga (2) resettalo al valore corretto.

Prova ad usarlo in :

class ValidationError extends Error { constructor(message) { super(message); this.name = "ValidationError"; }}// Usofunction readUser(json) { let user = JSON.parse(json); if (!user.age) { throw new ValidationError("Sin campo: age"); } if (!user.name) { throw new ValidationError("Sin campo: 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 campo: nombre } else if (err instanceof SyntaxError) { // (*) alert("Error de sintaxis JSON: " + err.message); } else { throw err; // error desconocido, vuelva a lanzarlo (**) }}

>

Il blocco try..catch nel codice precedente gestisce sia il nostro ValidationError come SyntaxError Incorporato JSON.parse.

Nota come utilizziamo instanceof per verificare il tipo di errore specifico su (*).

Potremmo anche guardare err.name, come questo:

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

è molto meglio, perché in il futuro che stiamo per estendere , faremo sottotipi di esso, come PropertyRequiredError. E controllo instanceof continuerà a funzionare per le nuove classi ereditate. Allora va in futuro.

È anche importante che se catch Trova un errore sconosciuto, quindi ri-lancialo sulla riga (**). Il blocco catch Solo sapere come gestire gli errori di convalida e sintassi, altri tipi (a causa di un errore tipografico nel codice o ad altri estranei) devono fallire.

Ereditarietà

classe ValidationError è molto generico. Molte cose possono sbagliare.La proprietà potrebbe essere assente o potrebbe essere in un formato errato (come valore di stringa per age). Facciamo una classe più concreta PropertyRequiredError, esattamente per le proprietà assenti. Prenderà ulteriori informazioni sulla proprietà mancante.

La nuova classe PropertyRequiredError è facile da usare: abbiamo solo bisogno di passare il nome della proprietà: new PropertyRequiredError(property) . Il message Leggibile umano è generato dal costruttore.

Si prega di notare che this.name nel costruttore PropertyRequiredError è assegnato manualmente di nuovo. Questo può diventare un po ‘noioso: Assegna this.name = <class name> in ogni classe di errore personalizzata. Possiamo evitarlo creando la nostra classe “Errore di base” che assegna this.name = this.constructor.name. E quindi ereditare tutti i nostri errori personalizzati.

Chiamalo MyError.

Ecco il codice con MyError e altre classi personalizzate, errore semplificato:

class MyError extends Error { constructor(message) { super(message); this.name = this.constructor.name; }}class ValidationError extends MyError { }class PropertyRequiredError extends ValidationError { constructor(property) { super("sin propiedad: " + property); this.property = property; }}// name es incorrectoalert( new PropertyRequiredError("campo").name ); // PropertyRequiredError

Ora gli errori personalizzati sono molto più corti, soprattutto ValidationError, poiché cancelliamo il nel costruttore.

Incarnato delle eccezioni

Lo scopo della funzione readUser nel codice precedente è “Leggi i dati dell’utente”. Ci possono essere diversi tipi di errori nel processo. In questo momento abbiamo SyntaxError e ValidationError, ma in futuro la funzione readUser può Crescere e probabilmente generare altri tipi di errori.

Il codice che chiama readUser deve gestire questi errori. In questo momento utilizza più if in blocco catch, che verifica la classe e gestire gli errori noti e lanciare nuovamente gli estranei.

Lo schema è come questo:

try { ... readUser() // la fuente potencial de error ...} catch (err) { if (err instanceof ValidationError) { // manejar errores de validación } else if (err instanceof SyntaxError) { // manejar errores de sintaxis } else { throw err; // error desconocido, vuelva a lanzarlo }}

Nel codice precedente possiamo vedere due tipi di errori, ma potrebbero esserci di più.

Se la funzione readUser Genera vari tipi di errori, quindi dobbiamo Chiedi a noi stessi: vogliamo davvero verificare tutti i tipi di errore uno per uno ogni volta?

Spesso, la risposta è “no”: vorremmo essere “un livello soprattutto”. Vogliamo solo sapere se ci fosse un “errore di lettura dei dati”: perché è successo esattamente è spesso irrilevante (il messaggio di errore lo descrive). O, meglio ancora, vorremmo avere un modo per ottenere i dettagli dell’errore, Ma solo se necessario.

La tecnica che abbiamo descritto qui si chiama “Eccezioni di imballaggio”.

  1. Creeremo una nuova classe ReadError per rappresentare un errore generico di “lettura dei dati”.
  2. La funzione readUser rileverà errori di lettura dei dati che si verificano al suo interno, come ValidationError e SyntaxError e generare un ReadError invece.
  3. L’oggetto

    manterrà il riferimento dell’errore originale sulla tua proprietà cause.

Quindi, il codice che chiama readUser dovrà solo verificare ReadError, non tutti i tipi di errori di lettura D Atos. E se hai bisogno di maggiori dettagli di un errore, puoi controllare la tua proprietà cause.

Ecco il codice che definisce ReadError e dimostra il suo utilizzo in readUser e 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; }}

nel codice precedente, readUser funziona Esattamente come se descrizione: rileva gli errori di sintassi e di convalida e getta gli errori ReadError invece (gli errori sconosciuti vengono generati come al solito).

Quindi, il codice esterno verifica instanceof ReadError E questo è tutto. Non è necessario elencare tutti i possibili tipi di errore.

La messa a fuoco è chiamata “Eccezioni di imballaggio”, perché prendiamo eccezioni “basso livello” e “Regola” in ReadError che è più astratto. È ampiamente utilizzato nella programmazione orientata agli oggetti.

Summary

  • Possiamo ereditare da Error E altre classi di errori gentilmente integrate. Abbiamo solo bisogno di prendersi cura della proprietà name e non dimenticare di chiamare super.
  • possiamo usare instanceof per verificare particolari errori. Funziona anche con l’ereditarietà.Ma a volte abbiamo un oggetto errore proveniente da una biblioteca di terze parti e non c’è modo semplice per ottenere la sua classe. Quindi la proprietà può essere utilizzato per tali controlli.
  • Exceptions Packet è una tecnica generalizzata: una funzione gestisce le eccezioni di basso livello e crea errori di alto livello in Luogo di diversi errori a basso livello. Le eccezioni di basso livello sono talvolta convertite in proprietà di quell’oggetto come negli esempi precedenti, ma non è strettamente necessario.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *