Welcome to Our Website

Errores personalizados, extendiendo Error

Cuando desarrollamos algo, a menudo necesitamos nuestras propias clases de error para reflejar cosas específicas que pueden salir mal en nuestras tareas. Para errores en operaciones de red podemos necesitar HttpError, para operaciones de base de datos DbError, para operaciones de búsqueda NotFoundError y así sucesivamente.

Nuestros errores deben apoyar error básico propiedades como message, name y, preferentemente, en el stack. Pero también pueden tener otras propiedades propias, por ej., HttpError objetos pueden tener un statusCode propiedad con un valor como 404 o 403 o 500.

JavaScript permite usar throwcon cualquier argumento, por lo que técnicamente nuestras clases de error personalizadas no necesitan heredar de Error. Pero si heredamos, entonces es posible usar obj instanceof Error para identificar objetos de error. Así que es mejor heredar de ella.

a medida que la aplicación crece, nuestros propios errores forman naturalmente una jerarquía., Por ejemplo, HttpTimeoutError puede heredar de HttpError, y así sucesivamente.

error de extensión

como ejemplo, consideremos una función readUser(json) que debería leer JSON con datos de usuario.

he Aquí un ejemplo de cómo un válido json puede buscar:

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

Internamente, vamos a utilizar la etiqueta JSON.parse. Si recibe un malformado json, entonces lanza SyntaxError., Pero incluso si json es sintácticamente correcto, eso no significa que sea un usuario válido, ¿verdad? Puede perder Los datos necesarios. Por ejemplo, puede que no tenga propiedades name y age que sean esenciales para nuestros usuarios.

Nuestra función readUser(json) no solo leerá JSON, sino que verificará («validará») los datos. Si no hay campos obligatorios, o el formato es incorrecto, entonces eso es un error. Y eso no es un SyntaxError, porque los datos son sintácticamente correctos, sino otro tipo de error., Lo llamaremos ValidationError y crearemos una clase para él. Un error de ese tipo también debe llevar la información sobre el campo infractor.

Nuestra clase ValidationError debe heredar de la clase incorporada Error.

esa clase está incorporada, pero aquí está su código aproximado para que podamos entender lo que estamos extendiendo:

ahora heredemos ValidationError de ella y pruébelo en acción:

tenga en cuenta: en la línea (1) llamamos al constructor padre., JavaScript requiere que llamemos a super en el constructor hijo, por lo que es obligatorio. El constructor padre establece la propiedad message.

El constructor padre también establece el name propiedad "Error", por lo que en la línea (2) nosotros para restablecer el valor correcto.,

Vamos a tratar de usarlo en el readUser(json):

El try..catch bloque en el código anterior se encarga tanto de nuestro ValidationError y la SyntaxError de JSON.parse.

eche un vistazo a cómo usamos instanceofpara verificar el tipo de error específico en la línea (*).,

también podríamos mirar err.name, como este:

// ...// instead of (err instanceof SyntaxError)} else if (err.name == "SyntaxError") { // (*)// ...

El instanceof versión es mucho mejor, porque en el futuro vamos a extender ValidationError, hacer subtipos, como lo es el PropertyRequiredError. Y instanceof check continuará funcionando para las nuevas clases herederas. Así que eso es a prueba de futuro.

también es importante que si catch encuentra un error desconocido, entonces lo vuelve a escribir en la línea (**)., El bloque catch solo sabe cómo manejar errores de validación y sintaxis, otros tipos (debido a un error tipográfico en el código u otros desconocidos) deberían caer.

más herencia

la clase ValidationError es muy genérica. Muchas cosas pueden salir mal. La propiedad puede estar ausente o puede estar en un formato incorrecto (como un valor de cadena para age). Vamos a hacer una clase más concreta PropertyRequiredError, exactamente para las propiedades ausentes. Llevará información adicional sobre la propiedad que falta.,

La nueva clase PropertyRequiredError es fácil de usar: sólo tenemos que pasar el nombre de la propiedad: new PropertyRequiredError(property). El constructor genera message legible por humanos.

tenga en cuenta que this.name in PropertyRequiredError constructor se asigna de nuevo manualmente. Eso puede volverse un poco tedioso: asignar this.name = <class name> en cada clase de error personalizada. Podemos evitarlo creando nuestra propia clase de «error básico»que asigna this.name = this.constructor.name. Y luego heredar todos nuestros errores personalizados de ella.,

vamos a llamarlo MyError.

Aquí está el código con MyError y otras clases de error personalizadas, simplificadas:

ahora los errores personalizados son mucho más cortos, especialmente ValidationError, ya que nos deshicimos de la línea "this.name = ..." en el constructor.

Wrapping exceptions

el propósito de la función readUser en el código anterior es «leer los datos del usuario». Puede haber diferentes tipos de errores en el proceso., Ahora mismo tenemos SyntaxError y ValidationError, pero en el futuro readUser función puede crecer y probablemente generar otros tipos de errores.

el código que llama a readUser debería manejar estos errores. En este momento utiliza múltiples ifs en el bloque catch, que comprueban la clase y manejan los errores conocidos y repiten los desconocidos.

El esquema es este:

En el código anterior podemos ver dos tipos de errores, pero puede haber más.,

si la función readUser genera varios tipos de errores, entonces debemos preguntarnos: ¿realmente queremos verificar todos los tipos de error uno por uno cada vez?

a menudo la respuesta es «No» :nos gustaría ser «un nivel por encima de todo eso». Solo queremos saber si hubo un «error de lectura de datos» – por qué exactamente sucedió a menudo es irrelevante (el mensaje de error lo describe). O, mejor aún, nos gustaría tener una manera de obtener los detalles del error, pero solo si es necesario.

la técnica que describimos aquí se llama «wrapping exceptions».,

  1. haremos una nueva clase ReadError para representar un error genérico de «lectura de datos».
  2. La función readUsercapturará los errores de lectura de datos que se produzcan dentro de ella, como ValidationErrory SyntaxError, y generará un ReadError en su lugar.
  3. El objetoReadError mantendrá la referencia al error original en su propiedadcause.,

entonces el código que llama a readUser solo tendrá que comprobar ReadError, no para todo tipo de errores de lectura de datos. Y si necesita más detalles de un error, puede verificar su propiedad cause.,

Aquí está el código que define ReadError y demuestra su uso en readUser y try..catch:

en el código anterior, readUser funciona exactamente como se describe – detecta errores de sintaxis y validación y lanza errores ReadError en su lugar (los errores desconocidos se repiten como de costumbre).

así que el código externo comprueba instanceof ReadError y eso es todo. No es necesario enumerar todos los posibles tipos de error.,

el enfoque se llama «envolviendo excepciones», porque tomamos excepciones de» bajo nivel «y las» envolvemos»en ReadError que es más abstracto. Es ampliamente utilizado en la programación orientada a objetos.

Summary

  • normalmente podemos heredar de Error y otras clases de error integradas. Solo tenemos que encargarnos de la propiedad name y no olvidemos llamar a super.
  • podemos usar instanceof para comprobar errores particulares. También funciona con la herencia., Pero a veces tenemos un objeto de error que proviene de una biblioteca de terceros y no hay una manera fácil de obtener su clase. Entonces name se puede usar la propiedad para tales comprobaciones.
  • Wrapping exceptions es una técnica extendida: una función maneja excepciones de bajo nivel y crea errores de alto nivel en lugar de varios de bajo nivel. Las excepciones de bajo nivel a veces se convierten en Propiedades de ese objeto como err.cause en los ejemplos anteriores, pero eso no es estrictamente necesario.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *