Skip to main content

Promises

Una Promise (promesa) es un objeto que representa el resultado eventual de una operación asíncrona. Las Promises hacen el código asíncrono más fácil de leer y mantener que los callbacks anidados.

¿Qué es una Promise?

Una Promise es un objeto que puede estar en uno de tres estados:
  • Pending (⏳ Pendiente): Estado inicial, la operación aún no ha terminado
  • Fulfilled (✅ Cumplida): La operación se completó exitosamente
  • Rejected (❌ Rechazada): La operación falló
const promise = new Promise((resolve, reject) => {
  // Operación asíncrona aquí
});

console.log(promise); // Promise { <pending> }
Una vez que una Promise está fulfilled o rejected, su estado no puede cambiar. Se dice que está “settled” (resuelta).

Crear una Promise

Para crear una Promise, usas el constructor Promise con una función que recibe dos parámetros: resolve y reject.

Promise Resuelta (Fulfilled)

const resolvePromiseBtn = document.getElementById("promise-resolved");

resolvePromiseBtn.addEventListener("click", function () {
  const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("✅ Operación exitosa");
    }, 2000);
  });

  console.log(promise);

  promise
    .then((mensaje) => console.log(mensaje))
    .catch((error) => console.log(error));
});
Flujo de ejecución:
  1. Se crea la Promise (estado: pending)
  2. Se imprime la Promise en la consola (muestra Promise { <pending> })
  3. Después de 2 segundos, se llama a resolve()
  4. La Promise cambia a estado fulfilled
  5. Se ejecuta el callback en .then()
  6. Se imprime ”✅ Operación exitosa”

Promise Rechazada (Rejected)

const rejectPromiseBtn = document.getElementById("promise-rejected");

rejectPromiseBtn.addEventListener("click", function () {
  const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
      reject("❌ Hubo un error");
    }, 2000);
  });

  promise
    .then((mensaje) => console.log(mensaje))
    .catch((error) => console.log(error));
});
Flujo de ejecución:
  1. Se crea la Promise
  2. Después de 2 segundos, se llama a reject()
  3. La Promise cambia a estado rejected
  4. Se salta el .then() y se ejecuta .catch()
  5. Se imprime ”❌ Hubo un error”
Si una Promise es rejected y no tienes un .catch(), obtendrás un error “Unhandled Promise Rejection” en la consola.

Consumir Promises: .then() y .catch()

Una vez que tienes una Promise, la “consumes” con .then() y .catch():
promise
  .then((resultado) => {
    // Se ejecuta si la Promise se resuelve exitosamente
    console.log('Exitoso:', resultado);
  })
  .catch((error) => {
    // Se ejecuta si la Promise es rechazada
    console.error('Error:', error);
  });

Métodos de Promise

Recibe dos funciones opcionales:
  • La primera se ejecuta si la Promise es fulfilled
  • La segunda se ejecuta si la Promise es rejected
promise.then(
  (resultado) => console.log('Exitoso:', resultado),
  (error) => console.error('Error:', error)
);
Retorna una nueva Promise, lo que permite encadenar.
Maneja errores. Es equivalente a .then(null, onRejected).
promise.catch((error) => {
  console.error('Error:', error);
});
También retorna una Promise, permitiendo encadenar más.
Se ejecuta siempre, sin importar si la Promise fue fulfilled o rejected.
promise
  .then(resultado => console.log(resultado))
  .catch(error => console.error(error))
  .finally(() => console.log('Operación completada'));
Útil para limpieza (ej: cerrar spinners de carga).

Encadenar Promises

Una de las grandes ventajas de las Promises es que puedes encadenarlas:
fetch('/api/user/1')
  .then((response) => {
    console.log('Respuesta recibida');
    return response.json(); // Retorna otra Promise
  })
  .then((data) => {
    console.log('Datos parseados:', data);
    return procesarDatos(data); // Retorna otra Promise
  })
  .then((resultado) => {
    console.log('Datos procesados:', resultado);
  })
  .catch((error) => {
    console.error('Error en cualquier paso:', error);
  });
Ventajas sobre callbacks:
  • Código más plano (no hay pirámide de callbacks)
  • Un solo .catch() maneja errores de todos los pasos
  • Más fácil de leer y mantener
Cada .then() retorna una nueva Promise. Si retornas un valor, se envuelve automáticamente en una Promise resuelta.

Ejemplo: De Callbacks a Promises

Con Callbacks (Callback Hell)

getUser(userId, (error, user) => {
  if (error) {
    console.error(error);
    return;
  }
  getOrders(user.id, (error, orders) => {
    if (error) {
      console.error(error);
      return;
    }
    processOrders(orders, (error, result) => {
      if (error) {
        console.error(error);
        return;
      }
      console.log('Resultado:', result);
    });
  });
});

Con Promises

getUser(userId)
  .then(user => getOrders(user.id))
  .then(orders => processOrders(orders))
  .then(result => console.log('Resultado:', result))
  .catch(error => console.error(error));
¡Mucho más limpio y fácil de leer!

Promise.all(): Múltiples Promises en Paralelo

Cuando necesitas esperar a que varias Promises terminen:
const promesa1 = fetch('/api/users');
const promesa2 = fetch('/api/products');
const promesa3 = fetch('/api/orders');

Promise.all([promesa1, promesa2, promesa3])
  .then(([usuarios, productos, ordenes]) => {
    console.log('Todas las peticiones completadas');
    console.log('Usuarios:', usuarios);
    console.log('Productos:', productos);
    console.log('Ordenes:', ordenes);
  })
  .catch(error => {
    console.error('Al menos una petición falló:', error);
  });
Características:
  • Espera a que todas las Promises se resuelvan
  • Si cualquiera falla, Promise.all() es rejected inmediatamente
  • Retorna un array con todos los resultados en el mismo orden

Otros Métodos de Promise

Retorna la Promise que termine primero (fulfilled o rejected).
const promesa1 = new Promise(resolve => setTimeout(() => resolve('Lento'), 2000));
const promesa2 = new Promise(resolve => setTimeout(() => resolve('Rápido'), 1000));

Promise.race([promesa1, promesa2])
  .then(resultado => console.log(resultado)); // "Rápido"
Útil para timeouts o racing conditions.

Manejo de Errores

Un .catch() para Todos

fetch('/api/data')
  .then(response => response.json())
  .then(data => procesarDatos(data))
  .then(resultado => mostrarResultado(resultado))
  .catch(error => {
    // Maneja errores de CUALQUIERA de los pasos anteriores
    console.error('Error en alguna parte:', error);
  });

.catch() en el Medio

fetch('/api/data')
  .then(response => response.json())
  .catch(error => {
    console.error('Error al obtener datos:', error);
    return { default: true }; // Valor por defecto
  })
  .then(data => {
    // Se ejecuta incluso si hubo error arriba
    console.log('Datos:', data);
  });
Si un .catch() no lanza un error, la cadena continúa normalmente. Esto permite recuperarse de errores.

Crear Promises de Valores

// Promise resuelta inmediatamente
const promesaResuelta = Promise.resolve('Valor');

// Promise rechazada inmediatamente
const promesaRechazada = Promise.reject(new Error('Error'));

// Útil para convertir valores en Promises
function obtenerDatos(cache) {
  if (cache) {
    return Promise.resolve(cache); // Retorna Promise
  }
  return fetch('/api/data'); // También retorna Promise
}

Buenas Prácticas

1

Siempre maneja errores

// ❌ Mal: Sin .catch()
fetch('/api/data').then(handleData);

// ✅ Bien: Con .catch()
fetch('/api/data')
  .then(handleData)
  .catch(handleError);
2

Retorna Promises en cadenas

// ❌ Mal: No retorna
promise.then(() => {
  otraPromise(); // Esta Promise se ignora
});

// ✅ Bien: Retorna la Promise
promise.then(() => {
  return otraPromise(); // Se encadena correctamente
});
3

Evita mezclar callbacks y Promises

// ❌ Confuso: Mezcla callbacks con Promises
fetch('/api/data').then(data => {
  setTimeout(() => {
    procesarDatos(data, (resultado) => {
      // ...
    });
  }, 1000);
});

// ✅ Mejor: Todo con Promises
fetch('/api/data')
  .then(data => esperarUnSegundo())
  .then(() => procesarDatosPromise(data));

Próximos Pasos

Async/Await

Aprende la sintaxis más moderna para trabajar con Promises

Fetch API

Usa Promises para hacer peticiones HTTP

Build docs developers (and LLMs) love