Tutorial de Javascript y las mejoras desde ES6 (ES2015) hasta ES10 (ES2019) – Parte 5 (Gestión de errores)

Gestión de errores (Error Handling)

La gestión de errores es una técnica que nos permite controlar los errores ocasionados durante la ejecución de nuestro código.

Si queremos realizar esa gestión de errores correctamente debemos conocer los tipos de error que existen.

  • Syntax Errors: Los errores de sintaxis ocurren en tiempo de interpretación.
    • function ()
      Uncaught SyntaxError: Function statements require a function name
    • Cuando ocurre este tipo de error solo el código contenido en el mismo hilo que el error de sintaxis se ve afectado, el resto se ejecuta asumiendo que nada de ellos depende del código que contiene el error.
  • Runtime Errors: Los errores de tiempo de ejecución (excepciones) ocurren durante la ejecución (después de la interpretación).
    • (() => {
        window.saludo();
      })();
      Uncaught TypeError: window.saludo is not a function
    • Las excepciones afectan en el hilo donde ocurren permitiendo que otros hilos continúen la ejecución normal.
  • Logical Errors: Este tipo de errores son muy complicados de localizar, ya que son el resultado de un error en la lógica del código no obteniendo el resultado esperado.

La sentencia try…catch…finally

Como ocurre en otros lenguajes de programación, Javascript también ofrece las sentencias try…catch…finally para la gestión de errores que junto al operador throw permite manejar las excepciones.

Para entender mejor como usar estas sentencias vamos a crear un sencillo ejemplo.

try {
  console.log('Ejecutamos TRY');
} catch (err) {
  console.log('Ejecutamos CATCH:', err);
} finally {
  console.log('Ejecutamos FINALLY');
}

// Ejecutamos TRY
// Ejecutamos FINALLY

try {
  console.log('Ejecutamos TRY');
  throw new Error('Lanzamos un error');
} catch (err) {
  console.log('Ejecutamos CATCH:', err);
} finally {
  console.log('Ejecutamos FINALLY');
}

// Ejecutamos TRY 
// Ejecutamos CATCH: Error: Lanzamos un error 
// Ejecutamos FINALLY

try {
  console.log('Ejecutamos TRY');
  window.saludo();
} catch (err) {
  console.log('Ejecutamos CATCH:', err);
} finally {
  console.log('Ejecutamos FINALLY');
}

// Ejecutamos TRY
// Ejecutamos CATCH: TypeError: window.saludo is not a function
// Ejecutamos FINALLY

Como hemos visto en el código anterior, la sentencia try debe ir seguido de catch finally.

Cuando ocurre una excepción en el bloque try  la excepción se pasa en err y se ejecuta el bloque catch.

El bloque (opcional) finally se ejecuta siempre después de try…catch.

Ahora que conocemos los tipos de errores y como se gestionan, vamos a realizar algunos ejemplos.

Tipos de errores en Javascript

Como vimos al principio de la entrada, los errores podían ser de un grupo u otro (Syntax, Runtime y Logical) dependiendo de varios factores.

Pero cuando necesitamos saber mas sobre el error ocurrido, Javascript ofrece múltiples constructores para tener mas detalle y poder realizar correctamente su gestión.

A continuación un listado de los constructores.

  • EvalError: Error asociado a la ejecución de la función eval().
  • try {
        throw new EvalError('Mensaje de prueba');
    } catch(err) {
        console.log('ERROR', err);
        // ERROR EvalError: Mensaje de prueba
    }
    
  • RangeError: Error asociado a un valor fuera del rango permitido para una variable o un parámetro.
  • try {
        var data = 1234.56;
        data.toFixed(-1)
    } catch(err) {
        console.log('ERROR', err);
        // ERROR RangeError: toFixed() digits argument must be between 0 and 100
    }
    
    try {
        throw new RangeError('Mensaje');
    } catch(err) {
        console.log('ERROR', err);
        // ERROR RangeError: Mensaje
    }
    
    
    const validarEdad = edad => {
       if (edad < 0 || edad >= 110) {
           throw new RangeError('La edad tiene que estar entre 0 y 110 años');
       }
    }
    
    try {
       validarEdad(200);
    } catch (err) {
       console.log('ERROR', err);
       // ERROR RangeError: El rango de edad es desde los 0 años hasta los 110 años
    }
    
    
    
    
  • ReferenceError: Error asociado a la invocación de una función u objeto y no existe en ese ámbito.
  • try {
        sumar();
    } catch(err) {
        console.log('ERROR', err);
        // ERROR ReferenceError: sumar is not defined
    }
    
    try {
        const total = 10 * iva;
    } catch(err) {
        console.log('ERROR', err);
        // ERROR ReferenceError: iva is not defined
    }
    
    try {
        throw new ReferenceError('Mensaje referencia');
    } catch(err) {
        console.log('ERROR', err);
        // ERROR ReferenceError: Mensaje referencia
    }
  • SyntaxError: Error en la sintaxis del código que se intenta ejecutar.
  • try {
        JSON.parse('{prueba de json invalido}')
    } catch(err) {
        console.log('ERROR', err);
        // ERROR SyntaxError: Unexpected token p in JSON at position 1
    }
    
    try {
        throw new SyntaxError('Mensaje syntax error');
    } catch(err) {
        console.log('ERROR', err);
        // ERROR SyntaxError: Mensaje syntax error
    }
    
    
  • TypeError: Error que sucede cuando una variable o parámetro no tienen un tipo válido.
  • try {
        throw new TypeError('Mensaje type');
    } catch(err) {
        console.log('ERROR', err);
        // ERROR TypeError: Mensaje type
    }
    
    const info = {
        nombre: 'text',
        estado: false,
        hello: () => {
            return 'Hello';
        },
    };
    try {
        console.log(info);
        console.log(info.nombre);
        console.log(info.hello());
        console.log(info.bye());
    } catch(err) {
        console.log('ERROR', err);
        /*
           {
               nombre: "text",
               estado: false,
               hello: () => { return 'Hello'; }
           }
           text
           Hello
           ERROR TypeError: info.bye is not a function
        */
    }
    
    
  • URIError: Error que ocurre cuando se pasan parámetros no válidos a las funciones encodeURI() ó decodeURl().
  • try {
        throw new URIError('URI error');
    } catch(err) {
        console.log('ERROR', err);
        // ERROR URIError: URI error
    }
    
    try {
        decodeURI('\\%%');
    } catch(err) {
        console.log('ERROR', err);
       // ERROR URIError: URI malformed
    }

Ahora, conociendo los constructores que nos ofrece Javascript podemos ser muchos mas específicos a la hora de gestionar y mostrar los errores.

Todo lo anterior esta fenomenal, pero…¿si necesito tener mi propio error o errores?.

A continuación te muestro como crear nuestros errores personalizados.

Creando nuestros errores personalizados

Cuando necesitamos lanzar un error personalizado de una forma simple podemos usar throw.

const nombre = '';
try {
   if (nombre.length === 0) {
      throw 'El campo nombre es obligatorio';
   }
} catch(err) {
   console.log(err);
   // El campo nombre es obligatorio
}

try { 
   if (nombre.length === 0) { 
      throw {code: 400, status: 'fail'}; 
   } 
} catch(err) { 
   console.log(err); 
   // {code: 400, status: "fail"}
}

El problema del ejemplo anterior, es que los errores que estamos mostrando no ofrecen ninguna información adicional.

Para tener nuestros errores personalizados y con toda la información necesaria usaremos el constructor Error().

try { 
   if (nombre.length === 0) { 
      throw new Error('El campo nombre es obligatorio'); 
   } 
} catch(err) { 
   console.log('ERROR NAME:', err.name); 
   // ERROR NAME: Error 
   console.log('ERROR MESSAGE:', err.message); 
   // ERROR MESSAGE: El campo nombre es obligatorio 
   console.log('ERROR STACK:', err.stack); 
   // ERROR STACK: Error: El campo nombre es obligatorio at snippet:///Script%20snippet%20%2321:3:7 
}

Como hemos podido observar la diferencia entre una u otra forma es bastante evidente.

Con esta entrada finalizamos lo que podríamos llamar el core de Javascript (fundamentos, operadores, control de flujo, array, etc…).

Para las siguientes entradas comenzaremos a revisar las nuevas características que esta ofreciendo Javascript, y que van desde ES6 (2015) hasta ES10 (2019).