Cuando una promesa falla y no existe un mecanismo que capture ese fallo, la aplicación puede romperse sin aviso. Comprender cómo gestionar los rechazos de forma limpia es fundamental para escribir código JavaScript robusto y profesional. Aquí se explica cómo catch y finally protegen toda una cadena de promesas.
¿Qué ocurre con un unhandled promise rejection?
Si realizamos un fetch a una URL que no existe y no añadimos ningún bloque que capture el error, el navegador lanza un unhandled promise rejection [0:23]. La cadena se detiene en silencio y no hay forma de saber qué salió mal a menos que revisemos la consola. Este comportamiento hace que el código sea frágil e impredecible.
javascript
fetch("https://apiquenoexiste.com/datos")
.then(res => res.json())
.then(data => console.log(data));
// Sin catch: la cadena muere en silencio
Para solucionar esto basta con agregar .catch() al final de la cadena [0:50]. Este método recibe el objeto de error y permite acceder a error.message para obtener una descripción clara del problema.
javascript
fetch("https://apiquenoexiste.com/datos")
.then(res => res.json())
.then(data => console.log(data))
.catch(error => console.log(error.message));
¿Por qué un solo catch protege toda la cadena?
Esta es una de las grandes ventajas de las promesas sobre los callbacks. Con callbacks era necesario manejar errores en cada nivel de anidación. Con promesas, un solo .catch() captura cualquier rechazo que ocurra en cualquier .then() previo [1:20]. JavaScript salta automáticamente todos los .then() intermedios hasta encontrar el próximo .catch().
¿Dónde se lanza el error importa?
Usando una API de excusas de desarrolladores como ejemplo [1:35], se puede observar un flujo interesante:
javascript
fetch("https://excuser-three.vercel.app/v1/excuse")
.then(res => res.json())
.then(data => {
console.log(data[0].excuse);
throw new Error("Falló tras obtener la excusa");
})
.then(() => console.log("Esto se salta"))
.catch(error => {
console.log("Capturado:", error.message);
return "Valor recuperado";
})
.then(valor => console.log(valor));
- La excusa se imprime correctamente: "It works on my machine" [2:28].
- El
throw fuerza un error, por lo que el siguiente .then() se salta por completo.
- El
.catch() captura el error y retorna un string normal.
- Como el valor retornado no es un error, la cadena continúa y el último
.then() sí se ejecuta [2:40].
¿Para qué sirve finally en las promesas?
El método .finally() ejecuta código sin importar si la promesa se resolvió o se rechazó [2:55]. No recibe ningún argumento y es perfecto para:
- Ocultar spinners de carga.
- Cerrar conexiones.
- Resetear variables de estado.
javascript
fetch("https://excuser-three.vercel.app/v1/excuse")
.then(res => res.json())
.then(data => console.log(data[0].excuse))
.catch(error => console.log(error.message))
.finally(() => {
console.log("Cargando: false");
});
Si la URL es válida, se muestra la excusa y luego el finally establece la carga en false [3:35]. Si la URL no existe, el .catch() captura el error y el .finally() se ejecuta de todas formas [3:55]. Siempre se ejecuta.
¿Cómo luce una cadena completa con buenas prácticas?
Una cadena de promesas bien estructurada sigue este patrón [4:10]:
javascript
function cargarExcusa() {
mostrarSpinner();
fetch("https://excuser-three.vercel.app/v1/excuse")
.then(res => {
if (!res.ok) throw new Error("Error en la respuesta");
return res.json();
})
.then(data => renderizar(data[0].excuse))
.catch(error => mostrarMensaje(error.message))
.finally(() => ocultarSpinner());
}
Este flujo garantiza que el spinner desaparezca siempre, tanto en éxito como en fallo.
¿Cuáles son los errores más comunes al trabajar con promesas?
- Olvidar retornar dentro del
.then(): rompe la cadena y los valores se pierden [4:35].
- No agregar
.catch(): genera rechazos no manejados que pueden romper la aplicación.
- Mezclar callbacks y promesas sin control: produce código confuso y difícil de depurar.
Con .catch() centralizamos el manejo de errores y con .finally() garantizamos la limpieza del estado. Ambos métodos convierten una cadena de promesas en un flujo secuencial, seguro y predecible. ¿Ya has enfrentado un unhandled promise rejection en tus proyectos? Comparte tu experiencia en los comentarios.