async/await y control de errores
async/await es azúcar sintáctico (syntactic sugar) introducido en ES2017 que facilita trabajar con Promises:
asyncindica que una función devuelve siempre una Promise.awaitdetiene la ejecución de la funciónasynchasta que la Promise se resuelva o rechace.
La gran ventaja es que permite escribir código asincrónico con un flujo más lineal y legible.
Ejemplo parcial
Veamos el mismo código, pero en 2 versiones:
- Promesas
- async/await
function getUser() {
return fetch('/user').then(res => res.json());
}
getUser()
.then(user => console.log(user))
.catch(error => console.error(error));
async function getUser() {
try {
const res = await fetch('/user');
const user = await res.json();
console.log(user);
} catch (error) {
console.error(error);
}
}
Características clave
-
Una función
asyncdevuelve siempre una Promise.async function foo() {
return 42; // Esto devuelve Promise.resolve(42)
} -
awaitsolo puede usarse dentro de funciones async (o en el tope de un módulo ES en entornos modernos). -
awaitpausa la función hasta que la Promise se resuelva o se rechace.
Flujo async/await y control de errores
Control de errores
Con Promises, usamos .catch(), pero con async/await, usamos try/catch:
async function processData() {
try {
const user = await fetchUser();
const orders = await fetchOrders(user.id);
console.log(orders);
} catch (error) {
console.error('Error en el flujo:', error);
}
}
Al igual que en Promises, podemos usar finally para ejecutar algo siempre, haya o no error:
async function runTask() {
try {
await task();
} catch (error) {
console.error(error);
} finally {
console.log('Siempre se ejecuta');
}
}
Ventajas
- Código más limpio y legible.
- Fácil de combinar con estructuras de control (
if,for,switch). - Permite manejar errores con
try/catchde forma clara. - Facilita la escritura de flujos asincrónicos complejos.
Buenas prácticas
-
Encadenar promesas en paralelo cuando no dependen entre si:
// Evita esto:
const user = await fetchUser();
const orders = await fetchOrders(user.id); // OK, depende de user
const settings = await fetchSettings(); // ❌ no depende, pero bloquea
// Mejor:
const user = await fetchUser();
const [orders, settings] = await Promise.all([
fetchOrders(user.id),
fetchSettings()
]); -
Siempre capturar errores:
- Usa
try/catchdentro de funcionesasync. - Usa
.catch()en el lugar donde se llama a la funciónasyncsi no se capturan internamente.
- Usa
-
No abusar de
awaitdentro de bucles. Considera paralelizar conPromise.all.
Ejemplo técnico
async function main() {
try {
const user = await fetchUser('123');
const [orders, settings] = await Promise.all([
fetchOrders(user.id),
fetchSettings()
]);
console.log('Usuario:', user);
console.log('Pedidos:', orders);
console.log('Ajustes:', settings);
} catch (error) {
console.error('Algo salió mal:', error);
} finally {
console.log('Proceso terminado');
}
}
Referencias
- Flanagan, D. (2020). JavaScript: The Definitive Guide (7th ed.). O’Reilly Media.
- Mozilla Developer Network. (s.f.). async function.
- Mozilla Developer Network. (s.f.). await.
- TypeScript Handbook. (s.f.). Async/Await.
- Google. (s.f.). JavaScript Style Guide.