• Sobre mí
  • Proyectos
  • Contacto
  • Blog

Apasionado por el desarrollo web y el diseño de interfaces intuitivas.

Cada error es un paso. Cada línea, un aprendizaje.

📍   Salou, Tarragona, España ✉️   [email protected] 📞   +34 641932611

Curriculum

Ver mi curriculum completo

Mapa del sitio

  • Inicio
  • Blog
  • Proyectos
  • Sobre mi
  • Mi misión
  • Sitemap

Contácto

  • Página de contácto
  • LinkedIn
  • GitHub

2026 Frankuxui - Todos los derechos reservados

  • Términos y condiciones
  • Política de privacidad
  • Política de cookies
Foto de unsplash creada por Avatar del usuario Mikolas Voborsky
Foto de unsplash creada por Avatar del usuario Mikolas Voborsky
  • JavaScript

Articulo publicado el 23 de julio de 2026

Por Frank Esteban Isdray Junco

Async/Await y Promises en JavaScript

Domina la programación asíncrona desde cero

La programación asincrónica es el corazón de cualquier aplicación JavaScript moderna. Desde solicitudes HTTP hasta temporizadores, casi todo en el navegador es asincrónico. En esta guía, te llevaré desde los Promises básicos hasta async/await avanzado, con ejemplos prácticos y patrones que realmente usas en producción.

¿Por qué necesitamos asincronía?

JavaScript es single-threaded: ejecuta una sola cosa a la vez. Sin asincronía, esperar una respuesta del servidor congelaría la interfaz completamente.

La asincronía permite que las operaciones largas ocurran "en segundo plano" mientras el código continúa ejecutándose.

javascript
// ❌ Sincrónico: congela todo
console.log("Inicio");
const data = fetch("/api/datos"); // Esto es imposible en sync
console.log(data);
console.log("Fin");

// ✅ Asincrónico: no congela
console.log("Inicio");
fetch("/api/datos").then((data) => console.log(data));
console.log("Fin");
// Salida: "Inicio", "Fin", [data]

¿Qué son los Promises?

Un Promise es un objeto que representa el resultado eventual de una operación asincrónica. Tiene tres estados posibles:

  • Pending (Pendiente): La operación aún no termina.
  • Fulfilled (Cumplido): La operación fue exitosa; el Promise tiene un valor.
  • Rejected (Rechazado): La operación falló; el Promise tiene un error.

Sintaxis básica de un Promise

javascript
const promise = new Promise((resolve, reject) => {
  // Simulamos una operación asincrónica
  setTimeout(() => {
    const success = true;

    if (success) {
      resolve("Operación exitosa");
    } else {
      reject("Algo salió mal");
    }
  }, 1000);
});

promise
  .then((result) => console.log(result)) // Ejecuta si cumple
  .catch((error) => console.error(error)); // Ejecuta si rechaza

Encadenamiento de Promises

Los Promises pueden encadenarse usando .then(), lo que permite que cada paso dependa del anterior:

javascript
fetch("/api/usuario/1")
  .then((response) => response.json())
  .then((user) => {
    console.log("Usuario:", user);
    return fetch(`/api/posts/${user.id}`);
  })
  .then((response) => response.json())
  .then((posts) => console.log("Posts:", posts))
  .catch((error) => console.error("Error:", error));

Introducción a Async/Await

Async/await es una forma más legible de escribir código asincrónico usando Promises. Convierte el código asincrónico en algo que se ve como sincrónico.

Sintaxis básica

javascript
async function fetchUser(id) {
  try {
    const response = await fetch(`/api/usuario/${id}`);
    const user = await response.json();
    return user;
  } catch (error) {
    console.error("Error al obtener usuario:", error);
  }
}

// Uso
fetchUser(1).then((user) => console.log(user));

¿Cómo funciona?

  • async: Marca una función como asincrónica. Siempre devuelve un Promise.
  • await: Pausa la ejecución hasta que el Promise se resuelva. Solo funciona dentro de funciones async.
javascript
async function ejemplo() {
  console.log("1. Inicio");

  const data = await fetch("/api/datos"); // Pausa aquí hasta recibir respuesta

  console.log("2. Datos recibidos:", data);
  console.log("3. Fin");
}

// Salida:
// 1. Inicio
// [Espera a que se resuelva el fetch]
// 2. Datos recibidos: Response {...}
// 3. Fin

Comparación: Promises vs Async/Await

Con Promises

javascript
function obtenerDatos() {
  return fetch("/api/usuario")
    .then((response) => response.json())
    .then((user) => fetch(`/api/posts/${user.id}`))
    .then((response) => response.json())
    .then((posts) => ({ user: user, posts: posts }))
    .catch((error) => console.error(error));
}

Con Async/Await

javascript
async function obtenerDatos() {
  try {
    const userResponse = await fetch("/api/usuario");
    const user = await userResponse.json();

    const postsResponse = await fetch(`/api/posts/${user.id}`);
    const posts = await postsResponse.json();

    return { user, posts };
  } catch (error) {
    console.error(error);
  }
}

Async/await es más legible y se parece más a código sincrónico.

Manejo de errores

Con try/catch

javascript
async function descargarArchivo(url) {
  try {
    const response = await fetch(url);

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }

    const data = await response.blob();
    return data;
  } catch (error) {
    console.error("Error al descargar:", error.message);
    throw error; // Re-lanzar si quieres
  }
}

Con Promises .catch()

javascript
fetch(url)
  .then((response) => {
    if (!response.ok) throw new Error(`HTTP ${response.status}`);
    return response.blob();
  })
  .catch((error) => console.error("Error:", error.message));

Operaciones paralelas vs secuenciales

Secuencial: Esperamos uno después del otro

javascript
async function procesarSecuencial() {
  const user = await fetch("/api/usuario/1").then((r) => r.json());
  const posts = await fetch(`/api/posts/${user.id}`).then((r) => r.json());
  const comments = await fetch(`/api/comments/${posts[0].id}`).then((r) => r.json());

  // Tiempo total: suma de todos los tiempos (lento)
  return { user, posts, comments };
}

Paralelo: Ejecutamos simultáneamente

javascript
async function procesarParalelo() {
  // Todas las solicitudes comienzan al mismo tiempo
  const [user, posts, comments] = await Promise.all([fetch("/api/usuario/1").then((r) => r.json()), fetch("/api/posts/1").then((r) => r.json()), fetch("/api/comments/1").then((r) => r.json())]);

  // Tiempo total: el máximo de los tres (más rápido)
  return { user, posts, comments };
}

#### Promise.all() vs Promise.race()

Promise.all(): Espera a que TODOS los Promises se resuelvan. Si uno falla, rechaza.

javascript
Promise.all([promise1, promise2, promise3])
  .then(([result1, result2, result3]) => {
    console.log("Todos completados:", result1, result2, result3);
  })
  .catch((error) => console.error("Alguno falló:", error));

Promise.race(): Devuelve el resultado del PRIMERO que se resuelva.

javascript
Promise.race([promise1, promise2])
  .then((result) => console.log("El primero en terminar:", result))
  .catch((error) => console.error("El primero falló:", error));
Promise.allSettled() para casos especiales

Si necesitas que se ejecuten todos los Promises sin importar si fallan:

javascript
const promesas = [fetch("/api/1").then((r) => r.json()), fetch("/api/2").then((r) => r.json()), fetch("/api/3").then((r) => r.json())];

const resultados = await Promise.allSettled(promesas);
// Devuelve: [
//   { status: 'fulfilled', value: data1 },
//   { status: 'rejected', reason: Error },
//   { status: 'fulfilled', value: data3 }
// ]

resultados.forEach((resultado, idx) => {
  if (resultado.status === "fulfilled") {
    console.log(`Promesa ${idx} exitosa:`, resultado.value);
  } else {
    console.log(`Promesa ${idx} falló:`, resultado.reason);
  }
});

Patrones avanzados

Implementar retry automático

javascript
async function fetchConReintentos(url, maxIntentos = 3) {
  for (let intento = 1; intento <= maxIntentos; intento++) {
    try {
      const response = await fetch(url);
      if (!response.ok) throw new Error(`HTTP ${response.status}`);
      return await response.json();
    } catch (error) {
      if (intento === maxIntentos) throw error;

      // Esperar antes de reintentar (backoff exponencial)
      const delay = Math.pow(2, intento - 1) * 1000;
      await new Promise((resolve) => setTimeout(resolve, delay));
    }
  }
}

// Usa
fetchConReintentos("/api/datos", 3)
  .then((data) => console.log(data))
  .catch((error) => console.error("Falló después de 3 intentos"));

Timeout para Promises

javascript
function conTimeout(promise, tiempoMs) {
  return Promise.race([promise, new Promise((_, reject) => setTimeout(() => reject(new Error("Timeout")), tiempoMs))]);
}

// Uso
conTimeout(fetch("/api/datos"), 5000)
  .then((response) => response.json())
  .catch((error) => console.error("Falló o excedió timeout"));

Resumen de mejores prácticas

  1. Usa async/await sobre Promises cuando sea posible: es más legible.
  2. Siempre maneja errores con try/catch o .catch().
  3. Paralleliza cuando puedas con Promise.all() en lugar de await secuencial.
  4. Entiende la diferencia entre operaciones que dependen unas de otras (secuencial) vs independientes (paralelo).
  5. Evita callback hell nunca volviendo a callbacks cuando tienes Promises.
  6. No olvides await al llamar funciones async; sin await, obtienes un Promise sin esperar el resultado.

La programación asincrónica es fundamental en JavaScript moderno. Dominarla te abrirá las puertas a aplicaciones más responsivas, escalables y profesionales.

En este artículo

  1. ¿Por qué necesitamos asincronía?
  2. ¿Qué son los Promises?
  3. Sintaxis básica de un Promise
  4. Encadenamiento de Promises
  5. Introducción a Async/Await
  6. Sintaxis básica
  7. ¿Cómo funciona?
  8. Comparación: Promises vs Async/Await
  9. Con Promises
  10. Con Async/Await
  11. Manejo de errores
  12. Con try/catch
  13. Con Promises .catch()
  14. Operaciones paralelas vs secuenciales
  15. Secuencial: Esperamos uno después del otro
  16. Paralelo: Ejecutamos simultáneamente
  17. #### Promise.all() vs Promise.race()
  18. Patrones avanzados
  19. Implementar retry automático
  20. Timeout para Promises
  21. Resumen de mejores prácticas

Articulos relacionados

Estos articulos pueden interesarte si te gusto este articulo.

Imagen de unsplash creada por Peter Burdon
Imagen del articulo Fotografía de Unsplash
23 de julio de 2026
JavaScript

Debounce y Throttle: Controla la frecuencia de ejecución de funciones

Optimiza el rendimiento de tu aplicación limitando cuántas veces se ejecutan listeners de eventos y funciones costosas

Imagen de unsplash creada por Frans Ruiter
Imagen del articulo Fotografía de Unsplash
23 de julio de 2026
JavaScript

Event Delegation en JavaScript Vanilla: Optimiza tu DOM

Cómo reducir listeners y mejorar el rendimiento usando bubbling de eventos

Fotografía de Unsplash creada por Natalia Rudomin
Imagen del articulo Tabs accesibles y escalables en JavaScript Vanilla
23 de julio de 2026
JavaScript
·Componentes
·Accesibilidad

Tabs reutilizables con JavaScript Vanilla

Un componente accesible, reutilizable y escalable con API programatica, teclado, ARIA y registro interno