Error Handling en Promesas: Manejo de Errores en JavaScript
Aprende técnicas avanzadas para manejar errores en promesas usando catch(), reject() y patrones de error handling robustos. Domina la propagación de errores y crea código asíncrono más resiliente.
TL;DR - Resumen rápido
- El método catch() captura errores de promesas rechazadas en la cadena
- La función reject() rechaza una promesa con un error específico
- Los errores en promesas se propagan automáticamente hasta encontrar un catch()
- Puedes encadenar múltiples catch() para manejar diferentes tipos de errores
- finally() siempre se ejecuta, independientemente del resultado de la promesa
Introducción al Error Handling en Promesas
El manejo de errores en promesas es fundamental para escribir código asíncrono robusto y confiable. A diferencia del código síncrono, donde los errores pueden ser capturados con try/catch, las promesas requieren técnicas específicas como el método catch() y la función reject(). Entender cómo funcionan estas técnicas te permitirá crear aplicaciones más resilientes que manejen correctamente los errores inesperados.
Cuando trabajas con operaciones asíncronas, es inevitable que algunas fallen: peticiones HTTP pueden fallar, bases de datos pueden estar indisponibles, o timeouts pueden expirar. Un buen manejo de errores no solo previene que tu aplicación se rompa, sino que también te permite proporcionar una mejor experiencia al usuario mostrando mensajes claros y ofreciendo alternativas.
Importancia del error handling
El manejo de errores en promesas no es opcional - es esencial. Sin un manejo adecuado, los errores no capturados pueden causar que tu aplicación se comporte de manera impredecible o incluso que se cierre completamente. Un buen manejo de errores transforma fallos técnicos en experiencias controladas para el usuario.
Método catch()
El método catch() es la forma principal de capturar errores en promesas. Se encadena después de then() y captura cualquier error que ocurra en la promesa o en cualquiera de las promesas anteriores en la cadena. El catch() recibe como parámetro el error que causó el rechazo de la promesa.
En este ejemplo, la promesa se rechaza con un error, y el catch() lo captura inmediatamente. Es importante notar que el catch() captura errores tanto de la promesa actual como de cualquier then() anterior en la cadena. Esto permite centralizar el manejo de errores en un solo lugar, lo que hace el código más limpio y mantenible.
Múltiples catch() en la Cadena
Puedes encadenar múltiples catch() para manejar diferentes tipos de errores de manera específica. Esto es útil cuando quieres proporcionar diferentes respuestas según el tipo de error que ocurrió.
Aquí, el primer catch() maneja errores de red específicos, mientras que el segundo catch() captura cualquier otro tipo de error. Este patrón te permite proporcionar respuestas más específicas y útiles según el tipo de error que ocurrió, mejorando la experiencia del usuario.
Mejor práctica: errores específicos
Usa múltiples catch() cuando necesites manejar diferentes tipos de errores de manera específica. Esto te permite proporcionar mensajes más claros y acciones más apropiadas según el tipo de error que ocurrió, mejorando la experiencia del usuario.
Función reject()
La función reject() es el segundo parámetro del executor de una promesa y se usa para rechazar la promesa con un error específico. A diferencia de throw() en código síncrono, reject() no interrumpe la ejecución del código, simplemente marca la promesa como rechazada con el error proporcionado.
En este ejemplo, la promesa se rechaza usando reject() con un Error específico. Es importante siempre pasar objetos Error a reject() en lugar de strings o valores primitivos, ya que los objetos Error proporcionan información valiosa como el stack trace y el mensaje de error, lo que facilita el debugging.
reject() vs throw()
Aunque tanto reject() como throw() pueden causar errores en promesas, tienen comportamientos diferentes que es importante entender.
La diferencia clave es que throw() dentro de una promesa se convierte automáticamente en un reject(), pero throw() fuera de una promesa causa un error no manejado. Además, reject() es más explícito y claro en el contexto de promesas, lo que hace el código más legible.
Siempre usa objetos Error
Al usar reject() o throw(), siempre pasa objetos Error (new Error("mensaje")) en lugar de strings. Los objetos Error proporcionan stack traces útiles para debugging, información contextual sobre el error, y son compatibles con herramientas de análisis de errores.
Propagación de Errores
Los errores en promesas se propagan automáticamente a través de la cadena hasta encontrar un catch() que los capture. Esto significa que un error en una promesa puede ser capturado por cualquier catch() posterior en la cadena, lo que permite centralizar el manejo de errores.
- <strong>Propagación automática:</strong> Los errores se propagan automáticamente hasta encontrar un catch().
- <strong>Un solo catch:</strong> Un catch() puede capturar errores de múltiples then() anteriores.
- <strong>Orden de ejecución:</strong> Los then() después de un error no se ejecutan.
- <strong>finally() siempre:</strong> El método finally() se ejecuta siempre, incluso si hay errores.
- <strong>Error no capturado:</strong> Si no hay catch(), el error se propaga al contexto global.
En este ejemplo, el error en el primer then() se propaga automáticamente al catch(), que lo captura. Los then() posteriores no se ejecutan porque el error interrumpe la cadena. Este comportamiento es útil porque permite centralizar el manejo de errores en un solo lugar, incluso cuando tienes múltiples operaciones asíncronas encadenadas.
Advertencia: Errores no capturados
Si una promesa se rechaza y no hay catch() que la capture, el error se convierte en un "unhandled rejection". En navegadores modernos, esto puede causar advertencias en la consola y, en aplicaciones de producción, puede causar que la aplicación se comporte de manera impredecible. Siempre asegúrate de tener al menos un catch() al final de cada cadena de promesas.
Errores Comunes
Al trabajar con error handling en promesas, hay varios errores que los desarrolladores cometen frecuentemente. Conocer estos errores te ayudará a evitarlos y escribir código más robusto.
- <strong>No usar catch():</strong> Olvidar agregar catch() al final de la cadena causa errores no manejados.
- <strong>Rechazar con strings:</strong> Usar strings en lugar de objetos Error hace el debugging difícil.
- <strong>Ignorar errores:</strong> Tener catch() vacío o que no hace nada oculta problemas importantes.
- <strong>Múltiples catch() innecesarios:</strong> Un solo catch() al final suele ser suficiente.
- <strong>No usar finally():</strong> finally() es útil para limpieza de recursos, independientemente del resultado.
Advertencia: catch() vacío
Tener un catch() vacío o que solo hace console.log() es un anti-patrón. Los errores deben ser manejados de manera significativa: mostrar un mensaje al usuario, registrar el error para debugging, o intentar una recuperación. Ignorar errores hace que tu aplicación sea menos confiable y más difícil de mantener.
Resumen: Error Handling en Promesas
Conceptos principales:
- •El método catch() captura errores de promesas rechazadas en la cadena
- •La función reject() rechaza una promesa con un error específico
- •Los errores en promesas se propagan automáticamente hasta encontrar un catch()
- •finally() siempre se ejecuta, independientemente del resultado de la promesa
- •Es importante siempre usar objetos Error en reject() y throw()
- •Un solo catch() al final puede capturar errores de múltiples then()
Mejores prácticas:
- •Siempre incluye al menos un catch() al final de cada cadena de promesas
- •Usa objetos Error (new Error()) en lugar de strings para rechazar promesas
- •Maneja los errores de manera significativa, no solo con console.log()
- •Usa múltiples catch() cuando necesites manejar diferentes tipos de errores
- •Utiliza finally() para limpieza de recursos independientemente del resultado
- •Proporciona mensajes claros al usuario cuando ocurren errores