// js · Web Platform Advent #2
Promesas en JavaScript: guía práctica
Entiende las promesas de JavaScript — cómo crearlas, then/catch/finally, el encadenamiento y combinarlas con Promise.all, race, any y allSettled — con ejemplos ejecutables y los errores más comunes.
Una promesa es un objeto que representa un valor que aún no está listo. Es la base del JavaScript asíncrono: fetch(), los temporizadores, las lecturas de archivos en Node y la mayoría de las API modernas devuelven promesas. Una promesa siempre está en uno de tres estados — pendiente (pending), cumplida (fulfilled) o rechazada (rejected) — y una vez que se resuelve no vuelve a cambiar.
Crear una promesa
La mayor parte del tiempo consumes promesas que te entrega una API. Pero puedes crear una con el constructor Promise, que recibe una función ejecutora con resolve y reject:
const wait = (ms) => new Promise((resolve) => {
setTimeout(resolve, ms);
});
const fetchUser = (id) => new Promise((resolve, reject) => {
if (!id) reject(new Error('id requerido'));
else resolve({ id, name: 'Ada' });
}); Llamar a resolve(valor) cumple la promesa con ese valor; llamar a reject(error) la rechaza. Cualquier excepción lanzada de forma síncrona dentro de la ejecutora también rechaza la promesa.
then, catch y finally
Lees el resultado de una promesa con .then() para el éxito, .catch() para el fallo y .finally() para una limpieza que se ejecuta en ambos casos:
fetchUser(42)
.then((user) => console.log('Recibido', user.name))
.catch((err) => console.error('Falló:', err.message))
.finally(() => console.log('Hecho')); .then() puede recibir dos argumentos — onFulfilled y onRejected — pero un .catch() separado al final de la cadena es más claro y también captura los errores lanzados en los .then() anteriores.
El encadenamiento: el verdadero superpoder
Cada .then() devuelve una nueva promesa, por eso se encadenan. Lo que devuelvas de un manejador se convierte en la entrada del siguiente. Y lo más importante: si devuelves una promesa, la cadena espera a que se resuelva antes de continuar:
fetch('/api/user')
.then((res) => res.json()) // devuelve una promesa → la cadena espera
.then((user) => fetch('/api/posts?user=' + user.id))
.then((res) => res.json())
.then((posts) => console.log(posts.length, 'publicaciones'))
.catch((err) => console.error(err)); Un único .catch() al final maneja un rechazo de cualquier paso anterior, por lo que el encadenamiento supera a anidar callbacks.
Ejecutar promesas juntas
Cuando las tareas no dependen unas de otras, lánzalas en paralelo y combina los resultados. Cuatro métodos estáticos cubren los casos habituales:
Promise.all([...])— espera a que todas se cumplan; rechaza en cuanto una se rechaza. Devuelve un array de resultados en orden.Promise.allSettled([...])— espera a que todas terminen y nunca rechaza; devuelve un array de objetos{ status, value }o{ status, reason }.Promise.race([...])— se resuelve con la primera promesa que se resuelva, ya sea cumplida o rechazada.Promise.any([...])— se resuelve con la primera promesa cumplida; solo rechaza si todas se rechazan.
// Obtener tres recursos a la vez, fallar si alguno falla
const [user, posts, prefs] = await Promise.all([
fetch('/api/user').then((r) => r.json()),
fetch('/api/posts').then((r) => r.json()),
fetch('/api/prefs').then((r) => r.json()),
]);
// Igual, pero tolerando fallos individuales
const results = await Promise.allSettled([taskA(), taskB(), taskC()]);
results.forEach((r) => {
if (r.status === 'fulfilled') console.log('ok', r.value);
else console.warn('falló', r.reason);
}); Errores comunes
- Olvidar el return. Dentro de un
.then(), si llamas a una promesa pero no lareturn, la cadena no la espera — pierdes el orden y el manejo de errores. - Rechazos no manejados. Una promesa sin
.catch()(o sintry/catchalrededor deawait) produce ununhandledrejection. Maneja siempre los errores al final de la cadena. - Mezclar callbacks y promesas. No llames a
resolvedos veces, ni aresolveyrejecta la vez — solo cuenta la primera llamada; el resto se ignora en silencio. - La ejecutora corre de inmediato. La función que pasas a
new Promise()se ejecuta de forma síncrona, al instante — solo los callbacks de.then()se difieren.
Referencia rápida
| Objetivo | Método |
|---|---|
| Manejar el éxito | .then(onFulfilled) |
| Manejar el fallo | .catch(onRejected) |
| Limpiar en ambos casos | .finally(fn) |
| Todas deben tener éxito | Promise.all |
| Recoger cada resultado | Promise.allSettled |
| La primera en resolverse | Promise.race |
| La primera en cumplirse | Promise.any |
Las promesas son la fontanería bajo async/await, que no es más que una sintaxis más agradable sobre los mismos objetos. Una vez que el encadenamiento y los cuatro combinadores te resulten naturales, el JavaScript asíncrono deja de intimidar.