GUÍA · Asincronía

Promesas y async/await en JavaScript explicados

Qué es una promesa, cómo se usan then y catch, qué aporta async/await y cómo manejar errores en código asíncrono, con ejemplos que puedes ejecutar.

Una promesa representa un resultado que llegará más tarde y puede terminar bien (resuelta) o mal (rechazada); async/await es una forma de escribir código con promesas que se lee de arriba abajo. Ambas formas hacen lo mismo; cambia la sintaxis.

Los tres estados de una promesa

  • Pendiente: todavía no hay resultado.
  • Resuelta (fulfilled): terminó bien y tiene un valor.
  • Rechazada (rejected): falló y tiene un motivo.
JavaScript
const espera = (ms, valor) =>
  new Promise(resolve => setTimeout(() => resolve(valor), ms));

espera(500, 'Listo').then(mensaje => console.log(mensaje));
console.log('Esto se muestra primero');
// Esto se muestra primero
// Listo (medio segundo después)

JavaScript no se detiene a esperar: sigue ejecutando y vuelve cuando la promesa termina.

then, catch y finally

JavaScript
fetch('https://ejemplo.com/datos.json')
  .then(respuesta => respuesta.json())
  .then(datos => console.log(datos))
  .catch(error => console.log('Falló:', error.message))
  .finally(() => console.log('Terminó'));
  • then recibe el valor cuando la promesa se resuelve y devuelve otra promesa, por lo que se puede encadenar.
  • catch captura el rechazo de cualquier eslabón anterior.
  • finally se ejecuta siempre, útil para ocultar un indicador de carga.

async/await: el mismo flujo, más legible

JavaScript
async function cargarDatos() {
  try {
    const respuesta = await fetch('https://ejemplo.com/datos.json');
    if (!respuesta.ok) {
      throw new Error('Respuesta HTTP ' + respuesta.status);
    }
    const datos = await respuesta.json();
    console.log(datos);
  } catch (error) {
    console.log('Falló:', error.message);
  } finally {
    console.log('Terminó');
  }
}
cargarDatos();

Reglas clave:

  1. await solo se puede usar dentro de una función async (o en el nivel superior de un módulo).
  2. Una función async siempre devuelve una promesa.
  3. Los errores se capturan con try/catch, como en código normal.

Esperar varias tareas

Si las tareas no dependen entre sí, lánzalas a la vez:

JavaScript
const [a, b] = await Promise.all([
  espera(300, 'A'),
  espera(500, 'B')
]);
console.log(a, b); // A B (tarda ~500 ms, no 800)

Otras opciones: Promise.allSettled espera todas aunque alguna falle, y Promise.race devuelve la primera que termine.

Errores comunes

  • Olvidar await: obtienes la promesa en vez del valor (Promise { <pending> }).
  • Olvidar el catch: un rechazo sin manejar produce el aviso *Unhandled promise rejection*.
  • Usar await dentro de forEach: no espera a cada iteración. Usa for...of si necesitas ejecutar los pasos en secuencia.
  • Confiar en que fetch rechaza con errores HTTP: un 404 no rechaza la promesa; hay que comprobar respuesta.ok.

¿Cuál elegir?

Para flujos con varios pasos, async/await suele ser más claro. Para transformar un valor en una sola línea, then es suficiente. Puedes mezclarlos sin problema.

Última actualización: . Los ejemplos se han comprobado en un navegador actual y en Node.js.