Cómo funciona el Event Loop en JavaScript

Close-up of JavaScript code on a computer screen, showing web development programming.
Foto de Marek Prášil en Pexels

Si alguna vez te has preguntado por qué una llamada a setTimeout se ejecuta después de un fetch, la respuesta está en el Event Loop. En JavaScript, el bucle de eventos es el motor que permite que el código asíncrono se mezcle con el síncrono sin bloquear el hilo principal. En este artículo vamos a desglosar su funcionamiento y a ver ejemplos que faciliten su comprensión.

Conceptos básicos

El motor de JavaScript (V8, SpiderMonkey, etc.) ejecuta el código en un único hilo llamado thread principal. Cuando el motor encuentra una operación que no puede completarse inmediatamente –por ejemplo una petición de red o un temporizador– delega esa tarea al entorno (navegador o Node.js) y continúa ejecutando el resto del script.

Una vez que la operación externa se completa, su callback no se ejecuta de inmediato; primero debe pasar por la cola de tareas (task queue) y ser recogido por el Event Loop.

Cola de tareas y microtareas

En el modelo de ejecución existen dos colas principales:

  • Task queue (cola de tareas): contiene callbacks de setTimeout, setInterval, eventos de UI, etc.
  • Microtask queue (cola de microtareas): alberga callbacks de Promise.then, Promise.catch, queueMicrotask y MutationObserver.

El Event Loop sigue una regla sencilla: después de ejecutar un bloque de código síncrono, procesa todas las microtareas pendientes antes de pasar a la siguiente tarea de la cola de tareas. Esta prioridad de las microtareas es la razón por la que los then de una promesa se ejecutan antes que un setTimeout con 0 ms.

Ejemplo práctico

Veamos un fragmento que ilustra el orden de ejecución:

console.log('Inicio');

setTimeout(() => {
  console.log('Timeout');
}, 0);

Promise.resolve().then(() => {
  console.log('Promise 1');
}).then(() => {
  console.log('Promise 2');
});

console.log('Fin');

El resultado en la consola será:

Inicio
Fin
Promise 1
Promise 2
Timeout

Primero se ejecuta el código síncrono (Inicio y Fin). Después, el Event Loop procesa la microtarea de la promesa (Promise 1 y Promise 2). Sólo al vaciar la microtask queue pasa a la task queue y ejecuta el setTimeout.

Trucos y buenas prácticas

Entender el Event Loop permite evitar sorpresas en aplicaciones reales:

  • Evita bloquear el hilo: operaciones pesadas deben delegarse a Web Workers o dividirse en trozos con requestIdleCallback o setTimeout para que el UI siga respondiendo.
  • Ordena tus promesas: si necesitas que una tarea se ejecute después de todas las microtareas, usa setTimeout o queueMicrotask según el caso.
  • Gestiona errores: una promesa rechazada sin .catch se convierte en una microtarea que lanza una excepción no capturada, rompiendo el bucle.

Conclusión

El Event Loop es la columna vertebral que permite a JavaScript combinar código síncrono y asíncrono sin necesidad de hilos múltiples. Conocer la diferencia entre la cola de tareas y la de microtareas, y saber cuándo usar cada una, te ayudará a escribir código más predecible y performante. La próxima vez que veas un Promise o un setTimeout, recuerda que están esperando su turno en el bucle, y que la prioridad siempre la tienen las microtareas.