Skip to content

L52 - Promesas

Una Promise (promesa) es un objeto que representa la finalización (o fallo) eventual de una operación asíncrona. Es una forma más estructurada y legible de manejar asincronía que los callbacks tradicionales.

Una Promise tiene tres estados:

EstadoSignificado
pendingEstado inicial. La operación aún no ha terminado.
fulfilledLa operación se completó con éxito. → resolve(valor)
rejectedLa operación falló. → reject(error)

Una vez que una Promise pasa a fulfilled o rejected, su estado no puede cambiar (es inmutable).

const promesa = new Promise((resolve, reject) => {
// operación asíncrona
setTimeout(() => {
const exito = Math.random() > 0.3;
if (exito) {
resolve('✅ Operación exitosa');
} else {
reject(new Error('❌ Algo salió mal'));
}
}, 1000);
});
  • resolve(valor): cambia la promesa a fulfilled.
  • reject(error): cambia la promesa a rejected.
promesa
.then(resultado => {
console.log('Resuelta:', resultado);
})
.catch(error => {
console.error('Rechazada:', error.message);
});

Se ejecuta siempre, haya éxito o error:

promesa
.then(resultado => console.log(resultado))
.catch(error => console.error(error))
.finally(() => console.log('🏁 Operación terminada'));

Cada .then() devuelve una nueva Promise, lo que permite encadenar operaciones:

fetch('/api/usuario')
.then(res => res.json())
.then(usuario => fetch(`/api/pedidos/${usuario.id}`))
.then(res => res.json())
.then(pedidos => {
console.log('Pedidos del usuario:', pedidos);
})
.catch(error => {
console.error('Error en la cadena:', error);
});

Si cualquier .then() lanza una excepción o devuelve una Promise rechazada, el flujo salta al .catch() más cercano.

Ejecuta múltiples promesas en paralelo y espera a que todas se resuelvan. Si una falla, la promesa resultante se rechaza inmediatamente.

const [usuarios, productos, pedidos] = await Promise.all([
fetch('/api/usuarios').then(r => r.json()),
fetch('/api/productos').then(r => r.json()),
fetch('/api/pedidos').then(r => r.json()),
]);
console.log({ usuarios, productos, pedidos });

Devuelve la primera promesa que se resuelva o rechace (la más rápida):

const resultado = await Promise.race([
fetch('/api/datos'),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), 5000)
),
]);

Espera a que todas terminen, fallen o no, y devuelve un array con los resultados:

const resultados = await Promise.allSettled([
fetch('/api/a'),
fetch('/api/b'),
fetch('/api/c'),
]);
resultados.forEach(r => {
if (r.status === 'fulfilled') {
console.log('', r.value);
} else {
console.log('', r.reason);
}
});

Cada objeto tiene { status: 'fulfilled' | 'rejected', value?: ..., reason?: ... }.

  1. Olvidar return en el .then(): si no retornas un valor, el siguiente .then() recibe undefined.
  2. No capturar errores: una Promise rechazada sin .catch() genera un UnhandledPromiseRejection.
  3. Mezclar callbacks y promesas: usa promesas de forma consistente para evitar el callback hell.
  4. Confundir Promise.all() con Promise.allSettled(): el primero falla rápido, el segundo espera a todos.

📝 Patrón: promisificar una función callback

Section titled “📝 Patrón: promisificar una función callback”
function leerArchivoPromesa(ruta) {
return new Promise((resolve, reject) => {
fs.readFile(ruta, 'utf8', (err, data) => {
if (err) reject(err);
else resolve(data);
});
});
}

🎯 Regla de oro: toda función asíncrona debería devolver una Promise. Así siempre se puede consumir con .then() / await.