Saltar al contenido

Diferencia entre microtask y macrotask dentro de un contexto de bucle de eventos

Solución:

Una vuelta al ciclo del evento tendrá exactamente uno tarea que se está procesando desde el cola de macrotask (esta cola se llama simplemente cola de tareas en la especificación WHATWG). Una vez finalizado este macrotask, todos los disponibles microtareas se procesará, es decir, dentro del mismo ciclo de ida y vuelta. Mientras se procesan estas microtareas, pueden poner en cola aún más microtareas, que se ejecutarán todas una por una, hasta que se agote la cola de microtareas.

¿Cuáles son las consecuencias prácticas de esto?

Si un microtareas pone en cola de forma recursiva otras microtareas, puede que sea necesario un largo tiempo hasta que se procese la siguiente macrotarea. Esto significa que podría terminar con una IU bloqueada o algunas E / S terminadas inactivas en su aplicación.

Sin embargo, al menos en lo que respecta a la función process.nextTick de Node.js (qué colas microtareas), hay una protección incorporada contra dicho bloqueo mediante process.maxTickDepth. Este valor se establece en un valor predeterminado de 1000, lo que reduce el procesamiento posterior de microtareas después de que se alcanza este límite que permite la siguiente macrotask para ser procesado)

Entonces, ¿cuándo usar qué?

Básicamente, usa microtareas cuando necesitas hacer cosas de forma asincrónica de forma sincrónica (es decir, cuando dirías realizar esta (micro) tarea en el futuro más inmediato). De lo contrario, apégate a macrotasks.

Ejemplos de

macrotasks: setTimeout, setInterval, setImmediate, requestAnimationFrame, I / O, renderizado de UI
microtareas: process.nextTick, Promises, queueMicrotask, MutationObserver

Conceptos básicos en especificación:

  • Un bucle de eventos tiene una o más colas de tareas (la cola de tareas es una cola de macrotask).
  • Cada bucle de eventos tiene una cola de microtareas.
  • cola de tareas = cola de macrotask! = cola de microtask
  • una tarea puede insertarse en la cola de macrotask o en la cola de microtask
  • cuando una tarea se inserta en una cola (micro / macro), queremos decir que la preparación del trabajo ha finalizado, por lo que la tarea se puede ejecutar ahora.

Y el modelo de proceso de bucle de eventos es el siguiente:

cuando la pila de llamadas está vacía, siga los pasos-

  1. seleccione la tarea más antigua (tarea A) en las colas de tareas
  2. si la tarea A es nula (significa que las colas de tareas están vacías), vaya al paso 6
  3. establecer “tarea actualmente en ejecución” en “tarea A”
  4. ejecutar “tarea A” (significa ejecutar la función de devolución de llamada)
  5. establecer “tarea actualmente en ejecución” en nulo, eliminar “tarea A”
  6. realizar cola de microtask
    • (a) .seleccione la tarea más antigua (tarea x) en la cola de microtask
    • (b) .si la tarea x es nula (significa que las colas de microtask están vacías), salte al paso (g)
    • (c) establecer “tarea en ejecución” en “tarea x”
    • (d) .ejecutar “tarea x”
    • (e) establecer “tarea actualmente en ejecución” en nulo, eliminar “tarea x”
    • (f) .seleccione la siguiente tarea más antigua en la cola de microtask, salte al paso (b)
    • (g) Finalizar la cola de microtareas;
  7. salte al paso 1.

un modelo de proceso simplificado es el siguiente:

  1. ejecute la tarea más antigua en la cola de macrotask y luego elimínela.
  2. ejecute todas las tareas disponibles en la cola de microtask y luego elimínelas.
  3. siguiente ronda: ejecutar la siguiente tarea en la cola de macrotask (saltar paso 2)

Algo para recordar:

  1. cuando una tarea (en cola de macrotask) se está ejecutando, se pueden registrar nuevos eventos, por lo que se pueden crear nuevas tareas. A continuación se muestran dos nuevas tareas creadas:
    • La devolución de llamada de promiseA.then () es una tarea
      • PromesaA se resuelve / rechaza: la tarea se enviará a la cola de microtask en la ronda actual del bucle de eventos.
      • PromesaA está pendiente: la tarea se enviará a la cola de microtask en la próxima ronda del bucle de eventos (puede ser la próxima ronda)
    • La devolución de llamada de setTimeout (callback, n) es una tarea y se enviará a la cola de macrotask, incluso n es 0;
  2. La tarea en la cola de microtask se ejecutará en la ronda actual, mientras que la tarea en la cola de macrotask tiene que esperar a la siguiente ronda del bucle de eventos.
  3. todos sabemos que la devolución de llamada de “click”, “scroll”, “ajax”, “setTimeout” … son tareas, sin embargo, también debemos recordar que los códigos js como un todo en la etiqueta de script es una tarea (una macrotask) también.

Creo que no podemos discutir el ciclo de eventos separado de la pila, así que:

JS tiene tres “pilas”:

  • pila estándar para todas las llamadas síncronas (una función llama a otra, etc.)
  • cola de microtask (o cola de trabajos o pila de microtask) para todas las operaciones asincrónicas con mayor prioridad (process.nextTick, Promises, Object.observe, MutationObserver)
  • cola de macrotask (o cola de eventos, cola de tareas, cola de macrotask) para todas las operaciones asíncronas con menor prioridad (setTimeout, setInterval, setImmediate, requestAnimationFrame, I / O, renderizado de UI)
|=======|
| macro |
| [...] |
|       |
|=======|
| micro |
| [...] |
|       |
|=======|
| stack |
| [...] |
|       |
|=======|

Y el bucle de eventos funciona de esta manera:

  • ejecute todo de abajo hacia arriba desde la pila, y SOLO cuando la pila esté vacía, verifique lo que está sucediendo en las colas de arriba
  • verifique la micro pila y ejecute todo allí (si es necesario) con la ayuda de la pila, una micro tarea tras otra hasta que la cola de microtask esté vacía o no requiera ninguna ejecución y SOLAMENTE luego verifique la pila de macros
  • verifique la pila de macros y ejecute todo lo que hay allí (si es necesario) con la ayuda de la pila

La pila de Mico no se tocará si la pila no está vacía. La pila de macros no se tocará si la pila de micro no está vacía O no requiere ninguna ejecución.

En resumen: la cola de microtask es casi lo mismo que la cola de macrotask, pero esas tareas (process.nextTick, Promises, Object.observe, MutationObserver) tienen mayor prioridad que las macrotasks.

Micro es como macro pero con mayor prioridad.

Aquí tienes el código “definitivo” para entender todo.

console.log('stack [1]');
setTimeout(() => console.log("macro [2]"), 0);
setTimeout(() => console.log("macro [3]"), 1);

const p = Promise.resolve();
for(let i = 0; i < 3; i++) p.then(() => {
    setTimeout(() => {
        console.log('stack [4]')
        setTimeout(() => console.log("macro [5]"), 0);
        p.then(() => console.log('micro [6]'));
    }, 0);
    console.log("stack [7]");
});

console.log("macro [8]");

/* Result:
stack [1]
macro [8]

stack [7], stack [7], stack [7]

macro [2]
macro [3]

stack [4]
micro [6]
stack [4]
micro [6]
stack [4]
micro [6]

macro [5], macro [5], macro [5]
--------------------
but in node in versions < 11 (older versions) you will get something different


stack [1]
macro [8]

stack [7], stack [7], stack [7]

macro [2]
macro [3]

stack [4], stack [4], stack [4]
micro [6], micro [6], micro [6]

macro [5], macro [5], macro [5]

more info: https://blog.insiderattack.net/new-changes-to-timers-and-microtasks-from-node-v11-0-0-and-above-68d112743eb3
*/
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *