Manejo de Errores con Async/Await en JavaScript
El uso de async y await en JavaScript hace que el código asíncrono sea más legible y fácil de entender. Sin embargo, un aspecto crucial para mantener un flujo de trabajo robusto es el manejo de errores en funciones asíncronas.
En este artículo exploraremos cómo capturar errores con try/catch
, cómo utilizar finally
y algunas prácticas avanzadas para asegurar que el código sea confiable.
Captura de Errores con try/catch
en Funciones Asíncronas
Cuando trabajamos con async/await
, los errores se pueden capturar directamente en un bloque try/catch
, evitando el uso de .catch()
en cada llamada a una promesa. Esto permite gestionar todos los errores de la función en una sola sección, facilitando la depuración.
Ejemplo Básico de Manejo de Errores con try/catch
async function obtenerDatos() {
try {
const respuesta = await fetch('https://api.example.com/datos');
const datos = await respuesta.json();
console.log("Datos recibidos:", datos);
} catch (error) {
console.error("Error al obtener datos:", error.message);
}
}
obtenerDatos();
En el código anterior vemos que si ocurre algún error durante la solicitud HTTP o al convertir la respuesta a JSON, el bloque catch
captura el error, permitiendo manejarlo sin detener el flujo general del programa.
Validación y Manejo de Errores Condicionales
Con async/await
es común agregar validaciones en cada paso del proceso para asegurarse de que los datos o respuestas sean correctos antes de continuar. Esto permite manejar errores de manera condicional y específica.
Ejemplo: Validación de Respuesta
async function obtenerUsuario(id) {
try {
const respuesta = await fetch(`https://api.example.com/usuario/${id}`);
if (!respuesta.ok) {
throw new Error("Usuario no encontrado");
}
const usuario = await respuesta.json();
console.log("Datos del usuario:", usuario);
} catch (error) {
console.error("Error al obtener usuario:", error.message);
}
}
obtenerUsuario(5);
En este ejemplo se valida que la respuesta HTTP sea satisfactoria antes de intentar convertirla a JSON. Si la respuesta no es correcta (ok
es false
), el flujo lanza un error personalizado.
Ejecución Final con finally
en Funciones Asíncronas
finally
es una sección que se ejecuta después de try/catch
, independientemente de si hubo un error o no. Esto es útil para realizar tareas de limpieza o finalizar acciones sin importar el resultado.
async function procesarArchivo() {
try {
const archivo = await abrirArchivo('archivo.txt');
console.log("Archivo procesado:", archivo);
} catch (error) {
console.error("Error al procesar archivo:", error.message);
} finally {
console.log("Liberando recursos...");
cerrarArchivo();
}
}
procesarArchivo();
"Error al procesar archivo:"
"Liberando recursos..."
En este caso, el bloque finally
asegura que el archivo se cierre, independientemente de si la operación fue exitosa o fallida.
Uso de Funciones Auxiliares para Captura de Errores
Encapsular el manejo de errores en funciones auxiliares facilita la reutilización y reduce la repetición de código, especialmente cuando manejamos varias promesas en paralelo o en secuencia.
Ejemplo de Función Auxiliar para Manejo de Errores
async function manejarErrores(funcion) {
try {
return await funcion();
} catch (error) {
console.error("Error capturado:", error.message);
return null;
}
}
async function obtenerDatos() {
return await manejarErrores(async () => {
let respuesta = await fetch('https://api.example.com/datos');
return await respuesta.json();
});
}
obtenerDatos().then(datos => console.log(datos));
En el código anterior la función asíncrona manejarErrores
encapsula el bloque try/catch
, centralizando el manejo de errores. Esto es útil para evitar múltiples bloques try/catch
en el código.
Manejo de Errores en Funciones Paralelas con Promise.all
y async/await
Cuando se realizan múltiples operaciones en paralelo con Promise.all
, es esencial capturar los errores correctamente para asegurarse de que el flujo no se interrumpa si una de las promesas falla.
Ejemplo de Manejo de Errores en Promesas Paralelas
async function obtenerDatosParalelo() {
try {
let [usuario, pedidos] = await Promise.all([
fetch('https://api.example.com/usuario/1').then(res => res.json()),
fetch('https://api.example.com/pedidos/1').then(res => res.json())
]);
console.log("Datos del usuario:", usuario);
console.log("Datos de pedidos:", pedidos);
} catch (error) {
console.error("Error en las operaciones paralelas:", error.message);
}
}
obtenerDatosParalelo();
En este ejemplo, si una de las promesas falla, el catch
captura el error y evita que el flujo de ejecución falle por completo.
Buenas Prácticas para Manejo de Errores con async/await
Implementar buenas prácticas en el manejo de errores con async/await
ayuda a mantener el código más seguro y fácil de depurar.
- Centraliza la Captura de Errores con Funciones Auxiliares: Crear funciones que encapsulen bloques
try/catch
permite un manejo de errores más limpio y reutilizable. - Utiliza
finally
para Liberación de Recursos: Asegúrate de utilizarfinally
para liberar recursos como archivos, conexiones de red o memoria, sin importar el resultado de la operación. - Maneja Errores Específicos con Validaciones Condicionales: Agrega verificaciones y errores personalizados en funciones para capturar errores específicos y mejorar la comprensión del flujo.
Conclusión
El manejo de errores en funciones async/await
es fundamental para escribir código asíncrono robusto y seguro. Al capturar errores con try/catch
, utilizar finally
para limpieza y adoptar prácticas como encapsular bloques de captura en funciones, puedes asegurar que el código sea menos propenso a fallos inesperados. Estas prácticas mejoran la legibilidad y la confiabilidad de las aplicaciones asíncronas.