L57 - Microtasks vs Macrotareas
🧠 Concepto
Section titled “🧠 Concepto”No todas las tareas asíncronas son iguales. JavaScript tiene dos colas de tareas con diferente prioridad:
- Microtasks (Microtareas): tienen prioridad. Se ejecutan justo después de que el Call Stack se vacíe, antes de cualquier macrotarea.
- Macrotasks (Macrotareas): se ejecutan en el siguiente ciclo del Event Loop, después de que se hayan procesado todas las microtasks disponibles.
💻 Tipos de tareas
Section titled “💻 Tipos de tareas”Microtasks
Section titled “Microtasks”| Fuente | Ejemplo |
|---|---|
| Promesas | .then(), .catch(), .finally() |
queueMicrotask() | Función explícita para encolar microtasks |
MutationObserver | Observar cambios en el DOM |
process.nextTick() | Solo en Node.js (se ejecuta antes que otras microtasks) |
Macrotasks
Section titled “Macrotasks”| Fuente | Ejemplo |
|---|---|
setTimeout() | Timer con retardo |
setInterval() | Timer repetitivo |
setImmediate() | Solo en Node.js |
| I/O | Lectura/escritura de archivos, sockets |
| UI Events | click, keydown, mousemove… |
requestAnimationFrame | Antes del renderizado (técnicamente es una tarea especial) |
📝 Orden de ejecución
Section titled “📝 Orden de ejecución”El Event Loop sigue este orden:
- Ejecuta todo el código síncrono (Call Stack).
- Vacía todas las microtasks (cola de microtareas).
- Toma una macrotarea de la cola de macrotareas y la ejecuta.
- Vuelve al paso 2.
⚠️ Las microtasks se procesan hasta vaciar la cola antes de pasar a la siguiente macrotarea. Si una microtask encola otra microtask, esta también se ejecutará antes de la siguiente macrotarea.
🎯 Ejemplo clásico: Promise vs setTimeout
Section titled “🎯 Ejemplo clásico: Promise vs setTimeout”console.log('1 - síncrono');
setTimeout(() => { console.log('2 - macrotask (setTimeout)');}, 0);
Promise.resolve().then(() => { console.log('3 - microtask (Promise)');});
console.log('4 - síncrono');¿Qué imprime?
Section titled “¿Qué imprime?”1 - síncrono4 - síncrono3 - microtask (Promise)2 - macrotask (setTimeout)Explicación
Section titled “Explicación”- Se ejecuta
console.log('1')(síncrono). setTimeout(cb, 0)registra el callback como macrotarea en la Web API.- La Promise se resuelve con
Promise.resolve()y su.then()se encola como microtask. - Se ejecuta
console.log('4')(síncrono). - Call Stack vacío. Se procesan las microtasks: se ejecuta el
.then()→ imprime ‘3’. - Se procesa la siguiente macrotarea: se ejecuta el
setTimeout→ imprime ‘2’.
💻 Ejemplo más complejo: anidamiento
Section titled “💻 Ejemplo más complejo: anidamiento”console.log('A');
setTimeout(() => { console.log('B (macrotask)'); Promise.resolve().then(() => { console.log('C (microtask dentro de macrotask)'); });}, 0);
Promise.resolve().then(() => { console.log('D (microtask)'); setTimeout(() => { console.log('E (macrotask dentro de microtask)'); }, 0);});
console.log('F');
// Resultado:// A// F// D (microtask)// B (macrotask)// C (microtask dentro de B)// E (macrotask dentro de D → se encola después de B)⚠️ Peligro: microtasks infinitas
Section titled “⚠️ Peligro: microtasks infinitas”Si una microtask encola otra microtask y así sucesivamente, el Event Loop nunca llegará a las macrotareas, bloqueando el renderizado:
function loop() { Promise.resolve().then(loop);}
loop(); // ⚠️ Esto bloquea el navegador// El Call Stack nunca se vacía completamente📝 queueMicrotask()
Section titled “📝 queueMicrotask()”Forma explícita de encolar una microtask:
queueMicrotask(() => { console.log('Esto es una microtask');});🧠 Caso de uso real
Section titled “🧠 Caso de uso real”// Aplazar cambios en el DOM hasta que se hayan procesado datosdatosActualizados = true;
// Usamos una microtask para asegurarnos de que cualquier código síncrono pendiente terminequeueMicrotask(() => { if (datosActualizados) { actualizarUI(); }});🎯 Regla práctica
Section titled “🎯 Regla práctica”Síncrono (Call Stack) ↓Microtasks (Promesas, queueMicrotask) ← PRIORIDAD ↓Macrotasks (setTimeout, eventos I/O) ↓Renderizado del navegador🎯 Regla de oro: las Promesas se resuelven antes que los
setTimeout, aunque el delay sea 0. Siempre.