Saltar al contenido

Lección 3 de 12 · Lectura y práctica

Async/await: patrones seguros y errores comunes

Async/await: patrones seguros y errores comunes Las promesas y async/await son la forma moderna de escribir código asíncrono en Node. La sintaxis parece síncrona y eso la hace legible, pero esconde trampas que provocan fugas de.

Del concepto a la práctica

Taller de esta lección

Cuando dos operaciones asíncronas no dependen entre sí, Promise.all expresa la intención y evita sumar sus tiempos. Cuando una puede fallar sin invalidar las demás, Promise.allSettled conserva cada resultado.

Ejemplo resuelto

js
const delay = (ms, value, fail = false) => new Promise((resolve, reject) => {
  setTimeout(() => fail ? reject(new Error("alerts fallo")) : resolve(value), ms);
});
const getProfile = () => delay(80, { id: "u7" });
const getAlerts = () => delay(120, ["A1"]);
const [profile, alerts] = await Promise.all([
  getProfile('u7'),
  getAlerts('u7')
]);

Si tardan 80 y 120 milisegundos, el tiempo ideal se aproxima a 120, no a 200. Si getAlerts falla, el conjunto se rechaza; esa decisión es correcta si ambas respuestas son necesarias.

Ejecuta como módulo .mjs para permitir await al nivel superior. El rechazo de Promise.all no cancela las demás operaciones; usa cancelación cooperativa cuando esté soportada. Las duraciones80/120 son mínimos de timers ilustrativos y no un tiempo de pared exacto bajo carga. No declares 120ms como resultado garantizado ni sumes tiempos de tareas concurrentes.

Pruébalo

  1. Sustituye las funciones por promesas con retrasos de 80 y 120 ms.

  2. Mide el tiempo alrededor de Promise.all.

  3. Haz fallar la segunda promesa y comprueba que el catch recibe el error.

Error frecuente: lanzar una promesa sin await ni manejo. Corrige retornándola, esperándola o conectándola a un controlador de errores.

Ejercicio: cambia el agregado completo a Promise.allSettled([getProfile(),delay(120,null,true)]), no únicamente la segunda operación.

Comprueba tu resultado

recibes dos estados, uno fulfilled y otro rejected, sin perder el resultado correcto de la primera.

Navegador, API y base de datos conectados por solicitudes, consultas y respuestas en sentidos opuestos.
CursaloMapa de práctica
Del navegador a los datos

El navegador envía una solicitud a la API. El servidor valida la operación y consulta los datos; después devuelve una respuesta que el navegador puede mostrar. La base de datos se comunica con el servidor y no directamente con el navegador.

Ver la infografía en tamaño completo ↗

Async/await: patrones seguros y errores comunes

Las promesas y async/await son la forma moderna de escribir código asíncrono en Node. La sintaxis parece síncrona y eso la hace legible, pero esconde trampas que provocan fugas de memoria, peticiones que nunca responden y errores que se pierden en silencio. Dominar tres patrones te evita el 90% de los problemas.

1. Paralelizar cuando las operaciones son independientes

Si dos consultas no dependen una de la otra, esperarlas en secuencia desperdicia tiempo. Promise.all las lanza a la vez.

// Lento: 200ms + 150ms = 350ms
const user = await getUser(id);
const orders = await getOrders(id);

// Rápido: max(200ms, 150ms) = 200ms
const [user, orders] = await Promise.all([
  getUser(id),
  getOrders(id),
]);

Atención

Con Promise.all, si una promesa falla, todo el conjunto se rechaza. Cuando quieras el resultado de todas aunque alguna falle, usa Promise.allSettled y revisa el status de cada una.

2. Captura los errores en un solo lugar

En Express, en lugar de envolver cada handler en try/catch, usa un pequeño envoltorio que reenvía cualquier error al middleware de errores:

const asyncHandler = (fn) => (req, res, next) =>
  Promise.resolve(fn(req, res, next)).catch(next);

app.get('/users/:id', asyncHandler(async (req, res) => {
  const user = await getUser(req.params.id);
  if (!user) return res.status(404).json({ error: 'no encontrado' });
  res.json(user);
}));

3. No dejes promesas colgadas

Llamar a una función async sin await ni .catch() crea una promesa flotante: si falla, genera un unhandled rejection que puede tumbar el proceso. Si de verdad no quieres esperarla, captura su error explícitamente.

Tienes tres consultas independientes que tardan 100ms cada una. ¿Cómo las resuelves en ~100ms en vez de 300ms?

Promise.all lanza las tres a la vez y espera a que todas terminen, así el tiempo total es el de la más lenta. Encadenar awaits las hace secuenciales (300ms) y quitar el await deja promesas colgadas.

Ejercicio práctico

Objetivo: optimizar y blindar código asíncrono.

  1. Escribe dos funciones fakeFetch(ms, label) que resuelvan tras un setTimeout.
  2. Llámalas primero en secuencia con dos await y mide el tiempo con console.time.
  3. Conviértelas a Promise.all y compara los tiempos.
  4. Crea el envoltorio asyncHandler y úsalo en una ruta que lance un error a propósito; comprueba que el error llega al middleware global.

Entregable: el código con ambos tiempos comentados y la captura del error manejado sin que el proceso muera.

Para recordar

  • Promise.all para operaciones independientes; allSettled cuando toleras fallos parciales.
  • Un asyncHandler reenvía errores al middleware y evita try/catch repetido.
  • Toda promesa necesita un await o un .catch(); nunca la dejes flotando.

Sigue con Node.js y APIs con Express

Esta lección forma parte de un curso de Cursalo. Revisa su programa y elige entre la compra individual o el acceso a toda la escuela.

Si ya tenías acceso a este curso, entra con tu cuenta: tus derechos y tu progreso se conservan. No necesitas comprarlo de nuevo.

01 / ELEGIR UNA RUTA

El próximo paso

Aprende IA mientras construyes algo que sí necesitas.

Empieza por el curso inicial o explora el catálogo para encontrar una práctica alineada con tu trabajo.