personalizados, estendéndose erro

Cando desenvolver algo, que moitas veces precisan de nosas propias clases de erro para reflectir cousas específicas que poden dar mal nas nosas tarefas. Para erros nas operacións de rede, podemos necesitar HttpError, para operacións de base de datos , para operacións de busca NotFoundError, etc.

Os nosos erros deben soportar propiedades de erro básicas como message, name e, preferentemente, stack. Pero tamén poden ter outras propiedades propias, por exemplo, obxectos HttpError pode ter unha propiedade statusCode cun valor como ou 403 ou 500.

JavaScript permítelle usar con calquera argumento, polo que técnicamente as nosas clases de erro personalizadas non necesitan herdar de Error. Pero se herdamos, entón é posible usar obj instanceof Error para identificar o erro dos obxectos. Entón é mellor herdar del.

A medida que a aplicación crece, os nosos propios erros forman naturalmente unha xerarquía. Por exemplo, HttpTimeoutError pode herdar de HttpError e así por diante.

Extensión de erro

Como exemplo, considere unha función que debería ler JSON cos datos do usuario.

Aquí está un exemplo de como pode ser válido:

Internamente, imos usar JSON.parse. Se recibe mal formado, entón Shed SyntaxError. Pero aínda que é sintácticamente correcto, iso non significa que sexa un usuario válido, non? Pode perder os datos necesarios. Por exemplo, pode que non teña nome e propiedades de idade que son esenciais para os nosos usuarios.

A nosa función non só lerá JSON, senón que verificará (” Validar “) os datos. Se non hai campos obrigatorios ou o formato é incorrecto, entón é un erro. E iso non é un” sintaxeiro “, porque os datos son sintácticamente correctos, pero outro tipo de erro. Chamarémolo ValidationError e crear unha clase para el. Un erro dese tipo tamén debe levar a información sobre o campo mineral.

A nosa clase ValidationError debe herdar da clase integrada Error.

Este tipo está incorporado, pero aquí está o seu código aproximado para que poidamos entender o que estamos ampliando:

// 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 }}

agora imos herdar ValidationError e probalo en acción:

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: na liña (1) Chamamos ao Pai Builder. JavaScript require que chamemos super no fillo constructor, polo que é obrigatorio. O constructor de pais conxunta a propiedade message.

O constructor principal tamén establece a propiedade name en "Error", polo tanto, na liña (2) restablecela ao valor correcto.

Intente usalo en IV id = “4bfffEA8e0 “

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 (**) }}

o bloque try..catch no código anterior controla tanto o noso ValidationError como o SyntaxError Incorporado JSON.parse.

Nota Como usamos instanceof Para verificar o tipo de erro específico sobre a

.

Tamén poderiamos mirar err.name, así:

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

a versión IV = “4B7EA79B7A”

é moito mellor, porque en O futuro que imos ampliar , imos facer subtipos del, como . E controlinstanceofseguirá traballando para novas clases herdadas. Entón que vai ao futuro.

Tamén é importante que, se catch busca un erro descoñecido, entón volva a tiralo na liña (**). O bloque catch só sabe como xestionar erros de validación e sintaxe, outros tipos (debido a un erro tipográfico no código ou noutros estraños) debe fallar.

adicional Herdanza

clase ValidationError é moi xenérica. Moitas cousas poden ir mal.A propiedade pode estar ausente ou pode estar nun formato incorrecto (como valor de cadea para age). Imos facer unha clase de formigón máis , exactamente para as propiedades ausentes. Terá información adicional sobre a propiedade que falta.

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 }}

A nova clase é fácil de usar: só necesitamos pasar o nome da propiedade: new PropertyRequiredError(property) .. O message lexible é xerado polo constructor.

Por favor, teña en conta que this.name no constructor PropertyRequiredError é asignado de novo manualmente. Isto pode chegar a ser un pouco tedioso: asignar this.name = <class name> en cada clase de erro personalizado. Podemos evitalo facendo que a nosa propia clase “Erro básico” que asigne this.name = this.constructor.name e despois herdar todos os nosos erros personalizados.

Imos chamalo MyError.

Aquí está o código con MyError e outras clases personalizadas, Erro simplificado:

Agora os erros personalizados son moito máis curtos, especialmente ValidationError, desde que eliminamos a liña IV =” 28FE748D12 “

no constructor.

incorporado de excepcións

O propósito da función readUser no código anterior é “ler os datos do usuario”. Pode haber diferentes tipos de erros no proceso. Neste momento temos SyntaxError e ValidationError, pero no futuro a función readUser pode Crecer e probablemente xerar outros tipos de erros.

O código que chama readUser debe manexar estes erros. Neste momento usa múltiples if no bloque catch, que verifica a clase e xestione os erros coñecidos e xogue de novo aos estraños.

O esquema é así:

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 }}

No código anterior podemos ver dous tipos de erros, pero pode haber máis.

Se a función readUser xera varios tipos de erros, entón debemos Pregunta a nós mesmos: realmente queremos verificar todo tipo de erro un por un cada vez?

Moitas veces, a resposta é “Non”: queremos ser “un nivel por riba de todo isto”. Só queremos saber se houbo un “erro de lectura de datos”: por que pasou exactamente é moitas veces irrelevante (a mensaxe de erro descríbea). Ou, mellor aínda, queremos ter un xeito de obter os detalles do erro, pero só se é necesario.

A técnica que describimos aquí chámase “Excepcións de envasado”.

  1. Crearemos unha nova clase ReadError para representar un erro xenérico de “lectura de datos”.
  2. A función readUser detectará erros de lectura de datos que se producen dentro del, como ValidationError e SyntaxError e xerar un ReadError no seu lugar.
  3. o obxecto ReadError manterá a referencia orixinal de erro na súa propiedade cause.

Entón, o código que chama readUser só terá que verificar ReadError, non todos os tipos de er erros de lectura Atos. E se precisa máis detalles dun erro, pode comprobar a súa propiedade cause.

Aquí está o código que define ReadError e demostra o seu uso en 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; }}

no código anterior, readUser funciona Exactamente como describa: detecta os erros de sintaxe e validación e lanza os erros ReadError no seu lugar (os erros descoñecidos son xerados como de costume).

Entón, o código externo verifica instanceof ReadError e iso é todo. Non é necesario listar todos os tipos de erros posibles.

O foco chámase “excepcións de envasado”, porque tomamos excepcións “baixo nivel” e “axustar” en ReadError que é máis abstracto. É amplamente utilizado na programación orientada a obxectos.

Resumo

  • Podemos herdar de Error E outras clases de erros amablemente incorporadas. Só necesitamos coidar da propiedade name e non se esqueza de chamar super.
  • Podemos usar instanceof para verificar os erros particulares. Tamén funciona con herdanza.Pero ás veces temos un obxecto de erro que provén dunha biblioteca de terceiros e non hai forma fácil de obter a súa clase. Entón a propiedade pode usarse para tales controis.
  • Paquete de excepcións é unha técnica xeneralizada: unha función controla excepcións de baixo nivel e crea erros de alto nivel en Lugar de varios erros de baixo nivel. As excepcións de baixo nivel son ás veces convertidas en propiedades dese obxecto como err.cause nos exemplos anteriores, pero iso non é estrictamente necesario.

Deixa unha resposta

O teu enderezo electrónico non se publicará Os campos obrigatorios están marcados con *