then, catch y finally: Manejo de Promesas en JavaScript
Domina los métodos then(), catch() y finally() para manejar el resultado, errores y limpieza de promesas.
TL;DR - Resumen rápido
- then() maneja el resultado exitoso de una promesa
- catch() captura errores que ocurran en la promesa o en then()
- finally() se ejecuta siempre, sin importar si la promesa se resuelve o rechaza
- Puedes encadenar múltiples then() para ejecutar operaciones en secuencia
- El error en catch() captura errores de la promesa y de cualquier then() anterior
Introducción a then, catch y finally
Los métodos then(), catch() y finally() son los tres métodos principales que proporcionan las promesas para manejar su resultado. then()se ejecuta cuando la promesa se resuelve exitosamente, catch() captura errores, y finally() se ejecuta siempre, sin importar el resultado. Estos métodos te permiten escribir código asíncrono más legible y mantenible.
Entender cómo funcionan estos tres métodos es fundamental para dominar la programación asíncrona en JavaScript. then() y catch() se usan para manejar el resultado de la promesa, mientras que finally() es ideal para código de limpieza que debe ejecutarse siempre, como cerrar conexiones o liberar recursos.
¿Por qué son importantes?
Estos métodos son la base del encadenamiento de promesas (promise chaining), que te permite ejecutar múltiples operaciones asíncronas en secuencia de manera elegante. También son la base para entender async/await, que es azúcar sintáctico sobre estos métodos.
Método then()
El método then() maneja el resultado de una promesa y **retorna una nueva promesa**. Recibe dos callbacks opcionales: onFulfilled para cuando la promesa se cumple, y onRejected para cuando se rechaza. El valor retornado por el callback se convierte en el valor de la nueva promesa. Esta capacidad de retornar nuevas promesas es lo que permite el encadenamiento de promesas.
then() retorna una nueva promesa
Cada llamada a then() retorna una **nueva promesa** con el valor transformado. Si retornas un valor primitivo, la nueva promesa se resuelve con ese valor. Si retornas otra promesa, la nueva promesa espera a que esa promesa se resuelva. Si lanzas un error, la nueva promesa se rechaza. Este comportamiento es fundamental para el encadenamiento.
Encadenar then()
Una de las características más poderosas de las promesas es que puedes encadenar múltiples llamadas a then(). Cada then() recibe el valor de retorno del then() anterior, lo que te permite ejecutar operaciones asíncronas en secuencia de manera plana y legible.
Este ejemplo muestra cómo encadenar múltiples then(). Primero obtenemos el usuario, luego sus posts, y finalmente los comentarios de cada post. Cadathen() recibe el valor del anterior, lo que permite pasar datos de una operación a la siguiente. Esto elimina el Callback Hell.
- <strong>Encadenamiento</strong>: then() retorna una nueva promesa con el valor transformado
- <strong>Secuencial</strong>: Cada then() espera a que el anterior termine
- <strong>Transformación</strong>: Puedes transformar el valor en cada then()
- <strong>Legibilidad</strong>: Código más plano y fácil de leer que callbacks anidados
- <strong>Error propagation</strong>: Los errores se propagan al catch() más cercano
Método catch()
El método catch(onRejected) es azúcar sintáctico parathen(undefined, onRejected). Captura errores que ocurren en la promesa o en cualquier then() anterior en la cadena. catch() **también retorna una nueva promesa**, lo que significa que puedes encadenar más then() después de un catch() para recuperarte del error y continuar la cadena.
Manejo de Errores
catch() captura errores de dos fuentes: rechazos de la promesa (cuando llamas a reject()) y errores que ocurren dentro de cualquierthen() en la cadena. Esto significa que un solo catch() puede manejar errores de múltiples then(), lo que simplifica el manejo de errores en código asíncrono.
Este ejemplo muestra cómo catch() captura errores de la promesa y de los then() anteriores. El catch() captura el rechazo de la promesa y también cualquier error que ocurra en los then() de la cadena. Esto significa que solo necesitas un catch() al final para manejar todos los errores.
Recuperación de Errores
Después de un catch(), puedes encadenar más then() para recuperarte del error. Si catch() no lanza un error, la cadena continúa como si no hubiera pasado nada. Esto permite implementar lógica de recuperación o valores por defecto cuando algo falla: promesa.catch(() => valorPorDefecto).then(...)
Método finally()
El método finally(callback) se ejecuta siempre, sin importar si la promesa se resuelve o rechaza. El callback de finally() **no recibe argumentos** (no tiene acceso al valor o error) porque su propósito es ejecutar código que debe correr independientemente del resultado. finally() retorna una nueva promesa que resuelve o rechaza con el mismo valor/error de la promesa original, ignorando el valor retornado por el callback (a menos que el callback lance un error).
Casos de Uso de finally()
finally() es útil en varios escenarios: cuando necesitas ejecutar código de limpieza independientemente del resultado, cuando quieres medir el tiempo de ejecución de una operación, o cuando necesitas asegurar que cierto código se ejecute siempre. Es especialmente importante en operaciones que involucran recursos externos.
Este ejemplo muestra cómo usar finally() para limpieza de recursos. La función conectarBaseDatos() crea una conexión, yfinally() asegura que la conexión se cierre siempre, sin importar si la operación tiene éxito o falla. También muestra cómo medir el tiempo de ejecución.
- <strong>Siempre se ejecuta</strong>: finally() corre sin importar el resultado
- <strong>No recibe argumentos</strong>: El callback no tiene acceso al valor o al error
- <strong>Retorno ignorado</strong>: El valor retornado por el callback se ignora
- <strong>Pasa el valor original</strong>: La promesa resultante tiene el mismo valor/error
- <strong>Limpieza de recursos</strong>: Ideal para cerrar conexiones o liberar memoria
Errores Comunes con then, catch y finally
Los siguientes errores son comunes y pueden causar bugs sutiles o aplicaciones que crashean inesperadamente. Estos problemas suelen manifestarse como errores no capturados en producción o comportamientos inesperados en el flujo de la aplicación.
Error 1: No Manejar Errores en Promesas
No incluir un catch() en una cadena de promesas causa "unhandled promise rejection". En Node.js versiones recientes, esto termina el proceso con exit code 1. En navegadores, genera una advertencia en consola. Este error es especialmente peligroso porque puede pasar desapercibido en desarrollo pero causar crasheos en producción.
Este ejemplo demuestra el peligro de omitir catch(). Cuando la promesa se rechaza sin un manejador, Node.js genera una advertencia (y en versiones modernas, crashea el proceso). La solución es simple: siempre agregar .catch() al final de tu cadena de promesas, incluso si solo logeas el error. En producción, esto previene crasheos inesperados.
Error 2: Return en finally()
Intentar retornar valores desde finally() es un error común que confunde a desarrolladores. El valor retornado por el callback de finally() se ignora completamente (a menos que lances un error). La promesa resultante de finally()mantiene el valor o error original de la promesa anterior. finally() es transparente: no modifica el flujo de valores.
Este ejemplo demuestra claramente que el valor retornado por finally() se ignora. La promesa resultante resuelve con el valor del then() anterior ("VALOR ORIGINAL"), no con el valor retornado por finally(). La única excepción es si finally() lanza un error, en cuyo caso la promesa se rechaza con ese error. Usa finally() solo para efectos secundarios, no para transformar valores.
Advertencia de Return en finally()
El valor de retorno de finally() siempre se ignora. Si necesitas transformar el resultado de una promesa, hazlo en then() ocatch(). Usa finally() solo para efectos secundarios como limpieza de recursos.
Resumen: then, catch y finally
Conceptos principales:
- •then() maneja el resultado exitoso de una promesa
- •catch() captura errores de la promesa y de then() anteriores
- •finally() se ejecuta siempre, sin importar el resultado
- •Puedes encadenar múltiples then() para ejecutar operaciones en secuencia
- •Los errores se propagan hacia abajo en la cadena de promesas
Mejores prácticas:
- •Siempre incluye al menos un catch() al final de tu cadena de promesas
- •Usa finally() para limpieza de recursos que debe ejecutarse siempre
- •No retornes valores desde finally(), el valor se ignora
- •Usa then() para transformar valores, no finally()
- •Encadena then() en lugar de anidar callbacks para mejor legibilidad