Actualizado el

El bloque finally en JavaScript no es lo que parece

Cuando pensamos en manejo de errores en JavaScript, lo primero que se nos viene a la cabeza es el clásico try/catch. Pero hay un tercer componente en este duo que pasamos por alto: el bloque finally.

try {
  // Código que puede lanzar un error
} catch (err) {
  // Código que maneja el error
} finally {
  // Código que siempre se ejecuta 🤔
}

Aunque su propósito principal es asegurarse de que un conjunto de instrucciones siempre se ejecute, independientemente de lo que ocurra en el bloque try o catch, esconde un detalle que puede cambiar completamente el flujo de una función.

¿Qué hace exactamente el bloque finally?

El bloque finally está diseñado para ejecutar código sin importar el resultado de los bloques try o catch. Es ideal para limpiar recursos, cerrar conexiones, o cualquier tarea que deba ejecutarse de todas formas. Pero lo que realmente sorprende es que finally puede incluso sobrescribir valores de retorno o ignorar excepciones, sin que nos demos cuenta.

Vamos a empezar con un ejemplo simple que ilustra lo que ocurre cuando el bloque finally retorna un valor:

function ejemplo1() {
  try {
    return 'Primero';
  } finally {
    return 'Segundo';
  }
}

// => 'Segundo'

Se supone que el código debería devolver ‘Primero’, ya que esa es la instrucción dentro del bloque try. Sin embargo, el bloque finally toma el control y devuelve ‘Segundo’. Esto ocurre porque JavaScript permite que el valor de retorno de finally sobrescriba cualquier otro retorno previo.

¿Qué pasa con los errores?

Uno de los usos más comunes del bloque try es manejar errores. Veamos cómo se comporta el bloque finally cuando hay una excepción:

function ejemplo2() {
  try {
    throw new Error('Oppps! :|');
  } catch (e) {
    return 'Error capturado :)';
  } finally {
    return 'Finally es el que manda :D';
  }
}

// => 'Finally es el que manda :D'

Incluso cuando se lanza una excepción y es capturada en el bloque catch, finally sigue devolviendo su propio valor. El retorno del catch queda en el olvido y el bloque finally toma el control otra vez.

Excepciones atrapadas por finally

El comportamiento del bloque finally se vuelve aún más interesante cuando hay excepciones que deberían propagarse:

function ejemplo3() {
  try {
    throw new Error('Error inicial');
  } finally {
    return 'Finally captura todo';
  }
}

// => 'Finally captura todo'

A pesar de que lanzamos un error en el bloque try, el bloque finally interrumpe el flujo normal de las excepciones. Esto significa que no solo sobrescribe retornos, sino que también bloquea las excepciones. Hay que tener mucho cuidado, porque podríamos estar ocultando errores sin darnos cuenta.

Un caso extremo

Ahora, pongamos todo junto con un ejemplo más completo:


function ejemplo4() {
  try {
    throw new Error('Error del try');
  } catch (e) {
    throw new Error('Error del catch');
    return 'Error capturado';
  } finally {
    return 'Finally domina';
  }
}

// => 'Finally domina'

En este ejemplo, aunque estamos lanzando un segundo error dentro del bloque catch, el bloque finally sigue adelante y devuelve su valor, haciendo que los errores pasen desapercibidos.

Conclusión

El bloque finally en JavaScript es útil para asegurarse de que ciertos pasos se ejecuten, pero también tiene el poder de modificar el flujo de la función, ignorar errores y sobrescribir valores de retorno. Este comportamiento puede ser peligroso si no se utiliza correctamente, ya que podríamos perder información importante.

Bueno saberlo, ¿no crees?

Un par de cosas que puedes hacer para ayudarme antes de irte:

A ti te cuesta cero y a mí me ayuda un montón. 😊

Jorge Baumann aka Baumannzone
Escrito por J. Baumann

Jorge Baumann es JavaScript senior software engineer, creador de contenido y speaker. Vive en Madrid, le encanta el testing, dibujar con CSS y tiene un perro que se llama Rambo.

Conoce más sobre J. Baumann