DevPath · Aprende a programar ESPTEN

Asincronía: promesas y async/await

Microtareas vs macrotareas

Dos colas, no una

Antes vimos que setTimeout(fn, 0) se aplaza hasta que el código actual termina. Pero hay un detalle más fino: el event loop no tiene una cola, sino (al menos) dos, y no tienen la misma prioridad.

La regla de oro

Cada vez que el hilo principal termina una tarea, vacía por completo la cola de microtareas antes de tomar la siguiente macrotarea. Es decir: las microtareas son las "coladas" que pasan antes; las macrotareas esperan en la fila de atrás.

Piénsalo como una caja de supermercado: la macrotarea es el siguiente cliente con su carro lleno, pero antes de cobrarle, el cajero atiende a todos los que solo vienen "a preguntar algo rápido" (las microtareas). Aunque el cliente del carro llegara "primero" (delay 0), las preguntas rápidas se resuelven antes.

console.log("1: síncrono");
setTimeout(() => console.log("2: macrotarea (setTimeout 0)"), 0);
Promise.resolve().then(() => console.log("3: microtarea (.then)"));
console.log("4: síncrono");
// Orden de salida: 1, 4, 3, 2

Primero corre todo el código síncrono (1, 4). Luego, antes de tocar la macrotarea del setTimeout, se vacía la cola de microtareas (3). Solo entonces llega el turno de la macrotarea (2).

await también es una microtarea

El código que sigue a un await se reanuda como microtarea. Por eso, en la práctica, las promesas siempre "ganan" a un setTimeout(0) programado a la vez.

Cuidado: si encadenas muchísimas microtareas que generan más microtareas, puedes dejar sin turno a las macrotareas (incluido el renderizado de la página). Las microtareas son rápidas, pero no son gratis.

Ejemplos

El orden clásico de la entrevista

console.log("A");
setTimeout(() => console.log("B (setTimeout)"), 0);
Promise.resolve().then(() => console.log("C (then)"));
console.log("D");
// Salida: A, D, C, B

Microtareas encadenadas van antes que la macrotarea

setTimeout(() => console.log("macro"), 0);
Promise.resolve()
  .then(() => console.log("micro 1"))
  .then(() => console.log("micro 2"));
console.log("sincrono");
// Salida: sincrono, micro 1, micro 2, macro
Pon esto en práctica

DevPath es un curso práctico: aquí lees la teoría; en la app la pones en práctica con ejercicios que se ejecutan de verdad, sin conexión.

Empezar gratis en la app →
← async / await y Promise.allCombinadores de promesas →