Manejar excepciones

Categories:

Habrá ocasiones en que, aún cuando evaluemos el código, existan errores en producción sobre los cuáles no tengamos control directamente – por ejemplo al evaluar la respuesta de una API -. Si encontramos una sección – línea o líneas de código – donde suceden los errores con más frecuencia, podemos atrapar los errores para intentar dar una mejor solución.

/*
  Código con errores que vamos a solucionar
*/

function no_existe_la_funcion() {
    var foo = {};
    foo.bar();
}
//=> Uncaught TypeError: undefined is not a function

function no_existe_la_variable() {
  a++;
}
//=> Uncaught ReferenceError: a is not defined

try

Para atrapar los errores tenemos que indicarle a JavaScript que queremos evaluar un bloque de código.
Esto lo hacemos con la declaración try.

try {
  // Bloque de código 
  }

Al utilizar try JavaScript necesita una manera de atrapar los errores – si es que suceden – para eso, después try, es necesario crear otro bloque de código. En el siguiente bloque se va a atrapar el primer error que suceda dentro del bloque try.

Nota:
Hay que tomar en cuenta que el bloque try únicamente va a ejecutar desde la primer línea hasta la línea donde se encuentra el error. Si try envía una excepción para ser capturada y todavía existen líneas de código dentro del bloque try, estas no van a ser evaluadas.

catch

Esta función se encarga de “atrapar” las excepciones generadas en el bloque try.
La función catch necesita un parámetro que es la excepción que arroja el bloque try.
Si no existen errores en el bloque try no se ejecuta este bloque de código

try {
    // Bloque de código
   } catch(e) {
      // Atrapar la excepción e
      // Esta excepción representa el primer error que suceda en el bloque try
      // Si no existen errores en el bloque try no se ejecuta este bloque de código
   }

Si queremos realizar distintas acciones dependiendo del tipo de error utilizamos condicionales para evaluar el tipo de error.

try {
  // Código
  } catch (e) {
    // Atrapar errores
    // Podemos responder de manera distinta 
    // dependiendo del tipo de error.
    if (e.name == "TypeError") {
      console.log("Es un error de tipo.");
    } else if (e.name == "ReferenceError") {
      console.log("Es un error de referencia.");      
    } else {
      console.log("Es otro tipo de error.");
    }
  }

finally

También podemos definir un bloque el cuál se va a interpretar después de try si no existieron errores que atrapar o después de catch si try arrojó un error y se utilizó catch.

try {
    // Bloque de código
  } catch (e) {
    // Atrapar la excepción e
  } finally {
    // Bloque de código que se va a ejecutar: 
    // Si no hay errores: después de try
    // Si hay errores: después de catch
  }

Ejemplo de manejo de excepciones

Llegamos a la implementación de try / catch / finally para atrapar las excepciones generadas por el código que tenemos en la parte superior.

function no_existe_la_funcion_corregido () {
    try {
      var foo = {};      
      foo.bar();
    } catch ( e ) {
       console.log("Atrapamos el error: " + e.name + " que dice: " + e.message);
       foo.bar = function () {
         console.log("Función creada al tiempo de ejecución");
       }
       foo.bar();
    }      
}

//=> Atrapamos el error: TypeError que dice: undefined is not a function
//=> Función creada al tiempo de ejecución
function no_existe_la_variable_corregido() {
  try {
    a++;
  } catch ( e ) { 
     a = 1;
    /* 
      No utilicé var a para definir la variable aquí, porque 
      por "levantamiento" o hoisting declararía la variable 
      en la parte superior de la función y no se generaría 
      el error.
    */
    console.log("Ahora la variable a tiene el valor de: " + a);    
  } finally {
    console.log("Este bloque se ejecuta sin importar si hay error o no.");
  }
}

//=> Ahora la variable a tiene el valor de: 1
//=> Este bloque se ejecuta sin importar si hay error o no.

Aunque en el siguiente ejemplo atrapamos el error de que la variable a no está definida, al lanzar el error JavaScript no continúa con la ejecución del código dentro del bloque try, por lo tanto no se le asigna valor a las otras variables ni se realiza la suma.

function no_existe_la_variable_biz ( ) {  
  try {
    var uno, dos, suma;
    a++;
    uno = 1;
    dos = 2;
    suma = uno + dos;
    console.log(suma);
  } catch ( e ) { 
     a = 1;
     console.log("Ahora la variable a tiene el valor de: " + a);    
    /*
      Como el error se genera ANTES de que se le asigne valor
      a las variables uno, dos y se realice la operación suma
      la variable suma tiene un valor undefined.
    */
    console.log("Pero la variable suma tiene el valor de: " + suma);    
  } finally {
    console.log("Este bloque se ejecuta sin importar si hay error o no.");
  }
  
}

//=> Ahora la variable a tiene el valor de: 1
//=> Pero la variable suma tiene el valor de: undefined
//=> Este bloque se ejecuta sin importar si hay error o no.

Con el manejo de excepciones vas a tener una mejor manera de tratar con los imprevistos de tu código en producción.