Promesas y async/await en JavaScript
Introducción
Desde ES6, JavaScript cuenta con Promesas como la abstracción estándar para gestionar operaciones asíncronas. Con ES2017 llegó async/await, una sintaxis que simplifica el código y lo hace más legible, sin perder la potencia de las promesas bajo el capó.
¿Qué es una Promesa?
Una Promise representa el resultado futuro de una operación que puede completarse con resolve (éxito) o reject (error). Su estado evoluciona de pending a fulfilled o rejected.
const promesa = new Promise((resolve, reject) => {
// Simulamos una operación asincrónica
setTimeout(() => {
const exito = Math.random() > 0.5;
exito ? resolve('Operación exitosa') : reject(new Error('Fallo inesperado'));
}, 1000);
});
Manejo de una Promesa
El método .then() recibe el valor de resolve y .catch() captura los errores.
promesa
.then(resultado => console.log(resultado))
.catch(err => console.error('Error:', err.message));
Encadenamiento de Promesas
Para ejecutar varias operaciones secuenciales, se encadenan .then(). Cada then devuelve una nueva promesa.
obtenerUsuario()
.then(usuario => obtenerPedidos(usuario.id))
.then(pedidos => console.log('Pedidos:', pedidos))
.catch(err => console.error('Falló la cadena:', err));
async/await: la sintaxis moderna
Al declarar una función con async, podemos usar await dentro de ella para "pausar" la ejecución hasta que la promesa se resuelva, evitando los anidados .then().
async function procesarUsuario() {
try {
const usuario = await obtenerUsuario();
const pedidos = await obtenerPedidos(usuario.id);
console.log('Pedidos:', pedidos);
} catch (err) {
console.error('Error en async/await:', err);
}
}
procesarUsuario();
Comparativa rápida (dos columnas)
Promesas
- Encadenamiento explícito con
.then()y.catch(). - Mayor control sobre la ejecución paralela usando
Promise.all(). - Requiere manejo cuidadoso de errores en cada nivel.
async/await
- Código secuencial y más legible.
- Los errores se capturan con
try/catchtradicional. - Internamente sigue usando promesas; no elimina
Promise.all()ni otras APIs.
Mejores prácticas y troubleshooting
1️⃣ Evita crear promesas innecesarias
Si una función ya devuelve una promesa, no la envuelvas nuevamente con new Promise. Esto genera promise wrapping y dificulta el rastreo de errores.
// Mala práctica
function fetchDataBad(url) {
return new Promise((resolve, reject) => {
fetch(url).then(res => resolve(res)).catch(err => reject(err));
});
}
// Buena práctica
function fetchDataGood(url) {
return fetch(url);
}
2️⃣ Usa Promise.allSettled para operaciones parciales
Cuando necesites que todas las llamadas se ejecuten aunque algunas fallen, Promise.allSettled devuelve el estado de cada una.
const resultados = await Promise.allSettled([p1, p2, p3]);
resultados.forEach(r => {
if (r.status === 'fulfilled') console.log('Éxito:', r.value);
else console.warn('Falló:', r.reason);
});
3️⃣ Manejo de tiempo de espera (timeout)
JavaScript no tiene timeout nativo para promesas, pero puedes combinar Promise.race con setTimeout:
function withTimeout(promise, ms) {
const timeout = new Promise((_, reject) =>
setTimeout(() => reject(new Error('Tiempo de espera agotado')), ms)
);
return Promise.race([promise, timeout]);
}
await withTimeout(fetch(url), 5000);
Seguridad y consideraciones de rendimiento
- Inyección de código: Nunca evalúes datos externos dentro de
asyncsin sanitizarlos. - Bloqueo del event loop: Evita operaciones CPU‑intensivas dentro de funciones
async. Usaworker_threadso procesos separados. - Memoria: Cada
awaitmantiene el stack de la llamada; en bucles muy grandes, considera procesar en lotes para reducir presión de GC.
Compatibilidad y soporte
Las promesas están soportadas desde IE11 (con polyfill) y en todos los navegadores modernos. async/await requiere ES2017; para navegadores antiguos se recomienda Babel o regenerator-runtime.
| Entorno | Promesas | async/await |
|---|---|---|
| Chrome 55+ | Sí | Sí |
| Firefox 52+ | Sí | Sí |
| Safari 10.1+ | Sí | Sí |
| Node.js 7.6+ | Sí | Sí |
Conclusión
Las promesas siguen siendo la base de la asincronía en JavaScript, mientras que async/await brinda una capa de sintaxis que mejora la legibilidad y reduce la propensión a errores comunes. Dominar ambas permite elegir la herramienta adecuada según el caso de uso, optimizar rendimiento y escribir código robusto y mantenible.
Promesas y async/await en JavaScript: Guía completa y ejemplos prácticos