Kodokon kodokon.com

Asincronía en la práctica

Usa async/await en tus rutas y gestiona los errores asíncronos sin tumbar el servidor.

10 min · 3 preguntas

Abrir esta lección en Kodokon

Tus rutas reales no devuelven arrays en memoria: leen archivos, consultan una base de datos, llaman a otras APIs. Todas estas operaciones son asíncronas. Conoces async/await desde el curso de JavaScript; veamos cómo usarlos de forma limpia en un servidor. Primera buena noticia: una función de ruta puede ser async.

JAVASCRIPT
import express from "express";
import { readFile } from "node:fs/promises";

const app = express();

app.get("/report", async (req, res) => {
  const raw = await readFile("report.json", "utf8");
  res.json(JSON.parse(raw));
});

app.listen(3000);

Este código funciona... siempre que report.json exista. Si la lectura falla, la promesa se rechaza y, según la versión de Express, la petición se queda sin respuesta o el error se filtra en los logs. La regla profesional: cada ruta async gestiona sus errores, con try/catch y next(error).

JAVASCRIPT
app.get("/report", async (req, res, next) => {
  try {
    const raw = await readFile("report.json", "utf8");
    res.json(JSON.parse(raw));
  } catch (error) {
    next(error);
  }
});

next(error) pasa el error al gestor de errores centralizado. Es un middleware con cuatro parámetros, declarado después de todas las rutas. Un único lugar para registrar y dar formato a los errores: eso es lo que distingue una API mantenible de un proyecto de fin de semana.

JAVASCRIPT
app.use((err, req, res, next) => {
  console.error(err);
  res.status(500).json({
    error: "Internal server error"
  });
});
Siempre el último, después de las rutas

Un último reflejo que debes desarrollar: el paralelismo. Dos operaciones independientes encadenadas con dos await se ejecutan una tras otra. Promise.all las lanza juntas: el tiempo de respuesta es el de la más lenta, no la suma de las dos.

JAVASCRIPT
async function fetchUsers() {
  return [{ id: 1, name: "Ada" }];
}

async function fetchTasks() {
  return [{ id: 1, title: "Review the code" }];
}

app.get("/dashboard", async (req, res, next) => {
  try {
    const [users, tasks] = await Promise.all([
      fetchUsers(),
      fetchTasks()
    ]);
    res.json({ users, tasks });
  } catch (error) {
    next(error);
  }
});

Prueba de conocimientos

Comprueba que has retenido los puntos clave de esta lección.

  1. En una ruta async, ¿qué haces con un error capturado por catch?
    • Registrarlo con console.log y seguir adelante
    • Llamar a next(error) para pasarlo al gestor de errores
    • Reintentar la petición automáticamente
  2. Dos llamadas asíncronas independientes deben ejecutarse lo más rápido posible. ¿Qué enfoque eliges?
    • Encadenarlas con dos await sucesivos
    • Lanzarlas juntas con Promise.all
    • Usar setTimeout entre las dos
  3. ¿Cómo reconoce Express un middleware de gestión de errores?
    • Por su firma de cuatro parámetros, con err primero
    • Por el nombre de la función, que debe ser errorHandler
    • Por su posición al principio del archivo