Patrones async/await en JavaScript que debes conocer

Frontend2026-09-20TryQuickToolBox

La programación asíncrona es una parte fundamental del JavaScript moderno, y async/await la ha hecho mucho más legible. Pero muchos desarrolladores aún luchan con errores comunes: rechazos de promesas no controlados, peticiones secuenciales lentas o manejo de errores confuso. En este artículo, exploraremos patrones prácticos de async/await que puedes aplicar de inmediato para escribir código más limpio y eficiente.

1. Sintaxis básica de async/await

Una función async siempre devuelve una Promise. La palabra clave await pausa la ejecución hasta que la Promise se resuelve, y luego devuelve su valor resuelto. Si la Promise se rechaza, lanza un error que puedes capturar con try/catch.

async function fetchData() {
  try {
    const response = await fetch('/api/data');
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Fetch failed:', error);
  }
}

Esta es la base. Pero los escenarios del mundo real a menudo requieren enfoques más matizados.

2. Manejo de errores con elegancia

Una de las mayores ventajas de async/await es que puedes usar try/catch tanto para errores síncronos como asíncronos. Sin embargo, ten cuidado con múltiples llamadas await en un solo bloque try: si la primera falla, las siguientes no se ejecutarán.

Para mayor granularidad, puedes envolver cada await en su propio try/catch o usar una función auxiliar para evitar bloques try/catch repetitivos.

async function getUser(id) {
  try {
    const user = await fetchUser(id);
    return user;
  } catch (error) {
    console.error('Failed to fetch user:', error);
    throw error;
  }
}

3. Ejecutar promesas en paralelo

Esperar múltiples promesas independientes de forma secuencial es un error de rendimiento común. Si necesitas resultados de múltiples fuentes, usa Promise.all() para ejecutarlas de forma concurrente.

// Secuencial: lento
const user = await fetchUser();
const posts = await fetchPosts();

// Paralelo: rápido
const [user, posts] = await Promise.all([fetchUser(), fetchPosts()]);

Usa Promise.allSettled() cuando quieras esperar a que todas las promesas se resuelvan, independientemente de si se cumplen o se rechazan. Esto es útil cuando quieres recopilar resultados aunque algunas fallen.

4. Ejecución secuencial cuando el orden importa

A veces necesitas procesar elementos en orden, como cuando cada paso depende del anterior. En ese caso, usa un bucle for...of con await en lugar de forEach (que no espera a los callbacks asíncronos).

for (const item of items) {
  await processItem(item);
}

Si necesitas limitar la concurrencia, considera librerías como p-limit o implementa una cola simple.

5. Evitar la trampa de async/await en bucles

Usar await dentro de Array.prototype.forEach es un error clásico: forEach no espera al callback asíncrono, por lo que el bucle termina antes de que las promesas se resuelvan. Usa siempre for...of o map con Promise.all.

6. Async/await con timeouts

Para evitar peticiones colgadas, puedes hacer una carrera entre una promesa y un timeout.

function timeout(ms) {
  return new Promise((_, reject) =>
    setTimeout(() => reject(new Error('Timeout')), ms)
  );
}

await Promise.race([fetchData(), timeout(5000)]);

Este patrón es útil para llamadas a API que podrían colgarse.

7. Generadores asíncronos y for await...of

Los generadores asíncronos te permiten producir un flujo de valores de forma asíncrona. Puedes consumirlos con for await...of.

async function* fetchPages() {
  let page = 1;
  while (true) {
    const data = await fetch(`/api/items?page=${page}`);
    if (data.length === 0) break;
    yield data;
    page++;
  }
}

for await (const page of fetchPages()) {
  console.log(page);
}

Esto es ideal para APIs paginadas o streaming de datos.

8. Errores comunes y cómo evitarlos

9. Buenas prácticas para código async limpio

FAQ

¿Cuál es la diferencia entre async/await y Promises?

Async/await es azúcar sintáctico sobre Promises, haciendo que el código asíncrono parezca síncrono. Simplifica el encadenamiento y el manejo de errores con try/catch.

¿Puedo usar await dentro de un bucle forEach?

No, forEach no espera a los callbacks asíncronos. Usa for...of o Promise.all con map en su lugar.

¿Cómo ejecuto múltiples operaciones async en paralelo?

Usa Promise.all() para ejecutarlas de forma concurrente y esperar a que todas se resuelvan.

Cuando trabajes con APIs JSON, puedes formatear y validar respuestas rápidamente usando nuestro JSON Formatter.