Bucle de eventos de JavaScript, microtareas y macrotareas
JavaScript es un lenguaje potente que se usa a menudo en el desarrollo web, y uno de sus conceptos fundamentales es cómo maneja las operaciones asíncronas. Para hacer este concepto más claro para los principiantes, exploraremos el Bucle de eventos (Event Loop), y los roles de las microtareas y macrotareas, acompañados de ejemplos sencillos para demostrar cómo JavaScript gestiona diversas operaciones.
Resumen simplificado del bucle de eventos
El Bucle de eventos es un mecanismo que JavaScript utiliza para manejar la ejecución de código, eventos y mensajes de manera eficiente. Aquí tienes una forma fácil de visualizarlo:
- Pila (Stack): Aquí es donde comienza la ejecución de tu código JavaScript, de arriba hacia abajo, como apilar bloques.
- Montículo (Heap): Piensa en esto como el almacén de memoria para los objetos que crea tu código.
- Cola (Queue): JavaScript en realidad utiliza dos colas separadas: una cola de macrotareas (para temporizadores, eventos de la interfaz de usuario y E/S) y una cola de microtareas (para Promesas y
queueMicrotask).
El Bucle de eventos verifica continuamente la pila para ver si hay algo que deba ejecutarse. Si la pila está vacía, primero revisa la cola de microtareas. Una vez que la cola de microtareas está vacía, mira la cola de macrotareas para ver si hay tareas pendientes que ejecutar. Este ciclo permite a JavaScript realizar tareas como actualizaciones de la interfaz de usuario, manejar interacciones del usuario o buscar datos en segundo plano sin bloquear el hilo principal.
Aquí tienes un ejemplo sencillo para explicar cómo funciona el bucle de eventos de JavaScript, centrándose especialmente en el manejo de eventos asíncronos con setTimeout:
En este ejemplo:
console.log('Start');se ejecuta primero, imprimiendo "Start" en la consola.setTimeoutprograma una función de devolución de llamada (callback) para que se ejecute después de 1000 milisegundos (1 segundo). Sin embargo, no bloquea la ejecución del código siguiente.console.log('End');se ejecuta inmediatamente después de programar el temporizador, imprimiendo "End" en la consola.- Después de que el hilo principal esté libre y haya pasado el retraso de 1 segundo, el Bucle de eventos revisa primero la cola de microtareas. Si está vacía, pasa a la cola de macrotareas, encuentra la devolución de llamada de
setTimeouty la ejecuta, imprimiendo "Timeout Callback" en la consola.
Esta secuencia demuestra eficazmente cómo el bucle de eventos de JavaScript maneja las tareas y cómo utiliza la cola de tareas para gestionar eventos asíncronos como los temporizadores. La devolución de llamada de setTimeout es un ejemplo de una macrotarea que se procesa después de que el script actualmente en ejecución y todas las demás tareas pendientes hayan terminado. Esto garantiza que el código sincrónico se ejecute inmediatamente sin esperar al código asíncrono (como operaciones de E/S o temporizadores), lo que mantiene la aplicación receptiva.
Microtareas vs. Macrotareas
¿Qué son las macrotareas?
Las macrotareas son bloques de tareas que incluyen cosas como:
setTimeout: Retrasa la ejecución de un fragmento de código hasta que haya pasado al menos el tiempo que especificas.setInterval: Ejecuta continuamente un fragmento de código después de cada intervalo especificado.- Eventos y operaciones de E/S: Como hacer clic en un botón o cargar datos desde una fuente externa.
Cada macrotarea se completa antes de pasar a la siguiente.
¿Qué son las microtareas?
Las microtareas son pequeñas tareas que deben realizarse sin interrupciones. Estas incluyen:
- Resolución de Promesas: Acciones que prometes realizar cuando se complete otra tarea.
- Función
queueMicrotask: Añade microtareas directamente.
Las microtareas se procesan más rápido y con mayor frecuencia que las macrotareas. Se procesan después de cada macrotarea y antes de que el motor de JavaScript tome la siguiente macrotarea.
Ejemplos de código en el mundo real
Ejemplo 1: Usar setTimeout como una macrotarea
Imagina que quieres mostrar un mensaje en una página web después de 2 segundos.
Explicación: Este código configura un temporizador que espera 2 segundos antes de ejecutarse. Luego cambia el texto de un elemento en la página (requiere un entorno de navegador). Esta es una macrotarea porque está programada para ejecutarse de forma independiente al flujo principal del programa.
Ejemplo 2: Usar Promesas como microtareas
Digamos que quieres registrar un mensaje justo después de una tarea rápida, como actualizar un estado.
Explicación: Este código crea una promesa que se resuelve inmediatamente y luego ejecuta el código dentro de .then() tan pronto como la pila esté vacía. Esta es una microtarea porque es una tarea pequeña que necesita ejecutarse justo después del código actual.
Más sobre la prioridad de las micro y macrotareas
En JavaScript, como hemos aprendido, las tareas dentro del bucle de eventos se categorizan como microtareas o macrotareas, cada una con una prioridad específica. Las microtareas incluyen operaciones como el procesamiento de Promesas, y siempre tienen una prioridad más alta. Esto significa que, una vez que el script actual termina, el motor de JavaScript gestionará todas las microtareas pendientes antes de comenzar con cualquier macrotarea, como temporizadores o manejadores de eventos.
Aquí tienes un ejemplo sencillo para ver esto en acción:
Salida esperada:
Start
End
Promise 1
Promise 2
Timeout 1
Timeout 2Esta secuencia muestra cómo las microtareas (resoluciones de Promesas) se ejecutan inmediatamente después del código sincrónico, incluso antes de las macrotareas programadas para el mismo momento. Esta priorización garantiza que las tareas críticas, como la actualización de datos, se completen lo antes posible.
Conclusión
Comprender el Bucle de eventos, junto con las microtareas y macrotareas, puede mejorar significativamente tu capacidad para escribir JavaScript eficiente. Al saber cómo y cuándo JavaScript ejecuta tu código, puedes crear aplicaciones más receptivas y eficientes. La idea clave es usar macrotareas para tareas grandes y menos urgentes, y microtareas para trabajos pequeños e inmediatos. ¡Esta guía te ayudará a comprender los fundamentos y comenzar a aplicar estos conceptos en tus propios proyectos!
Práctica
En JavaScript, ¿qué sucede cuando una promesa se resuelve y hay un controlador `.then()` adjunto?