pasar - funciones javascript
Diferencia entre microtask y macrotask dentro de un contexto de bucle de eventos (3)
Acabo de leer la especificación Promesas / A + y me topé con los términos microtask y macrotask: consulte http://promisesaplus.com/#notes
Nunca he oído hablar de estos términos antes, y ahora tengo curiosidad por saber cuál sería la diferencia.
Ya he tratado de encontrar información en la web, pero todo lo que he encontrado es esta publicación de los Archivos de w3.org (que no me explica la diferencia): http://lists.w3.org/Archives/Public/public-nextweb/2013Jul/0018.html
Además, he encontrado un módulo npm llamado "macrotask": https://www.npmjs.org/package/macrotask Nuevamente, no se aclara cuál es la diferencia exactamente.
Todo lo que sé es que tiene algo que ver con el bucle de eventos, como se describe en https://html.spec.whatwg.org/multipage/webappapis.html#task-queue y https://html.spec.whatwg.org/multipage/webappapis.html#perform-a-microtask-checkpoint
Sé que teóricamente debería poder extraer las diferencias yo mismo, dada esta especificación WHATWG. Pero estoy seguro de que otros podrían beneficiarse también de una breve explicación dada por un experto.
Conceptos básicos en https://html.spec.whatwg.org/multipage/webappapis.html#task-queue :
- Un bucle de eventos tiene una o más colas de tareas (la cola de tareas es cola macrotask)
- Cada ciclo de evento tiene una cola de microtask.
- tarea cola = cola macrotask! = cola microtask
- una tarea se puede insertar 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:
- seleccione la tarea más antigua (tarea A) en las colas de tareas
- si la tarea A es nula (significa que las colas de tareas están vacías), vaya al paso 6
- establezca "tarea actualmente en ejecución" en "tarea A"
- ejecutar "tarea A" (significa ejecutar la función de devolución de llamada)
- establezca "tarea actualmente en ejecución" en nulo, elimine "tarea A"
-
realizar la 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), vaya al paso (g)
- (c) .set "tarea actualmente en ejecución" a "tarea x"
- (d) .run "tarea x"
- (e) .set "tarea actualmente en ejecución" a nulo, elimine "tarea x"
- (f) .seleccione la siguiente tarea más antigua en la cola de microtask, salte al paso (b)
- (g) .finish microtask queue;
- salta al paso 1.
Un modelo de proceso simplificado es el siguiente:
- ejecute la tarea más antigua en la cola de macrotask, luego quítela.
- ejecute todas las tareas disponibles en la cola de microtask, luego quítelas.
- siguiente ronda: ejecutar la siguiente tarea en la cola de macrotask (paso 2 de salto)
Algo para recordar:
-
cuando se ejecuta una tarea (en la cola de macrotask), 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
- Se resuelve / rechaza la promesaA: la tarea se incluirá en la cola de microtask en la ronda actual del ciclo de eventos
- promiseA está pendiente: la tarea se incluirá en la cola de microtask en la futura ronda del ciclo de eventos (puede ser la próxima ronda)
- La devolución de llamada de setTimeout (callback, n) es una tarea, y será empujada a la cola de macrotask, incluso n es 0;
-
La devolución de llamada de promiseA.then () es una tarea
- la tarea en la cola de microtask se ejecutará en la ronda actual, mientras que la tarea en la cola de macrotask debe esperar a la siguiente ronda del ciclo de eventos.
- todos sabemos que la devolución de llamada de "clic", "desplazamiento", "ajax", "setTimeout" ... son tareas, sin embargo, también debemos recordar que los códigos js en su conjunto en la etiqueta del script es una tarea (un macrotask) también.
Escribí una publicación sobre esto, que incluye ejemplos interactivos https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/
Actualización: También di una charla sobre este https://www.youtube.com/watch?v=cCOL7MC4Pl0 . La charla entra en más detalles, incluyendo cómo las tareas y microtasks interactúan con el renderizado.
Una vuelta del bucle de eventos tendrá exactamente una tarea procesada desde la cola macrotask (esta cola simplemente se llama cola de tareas en la https://html.spec.whatwg.org/multipage/webappapis.html#task-queue ). Una vez que esta macrotask haya finalizado, se procesarán todas las microtask disponibles, es decir, dentro del mismo ciclo de recorrido. Mientras se procesan estas microtask, pueden poner en cola aún más microtasks, que se ejecutarán una por una, hasta que se agote la cola de microtask.
¿Cuáles son las consecuencias prácticas de esto?
Si un microtask pone en cola recursivamente a otros microtask, puede pasar mucho tiempo hasta que se procese el siguiente macrotask. Esto significa que podría terminar con una IU bloqueada, o alguna E / S terminada inactiva en su aplicación.
Sin embargo, al menos con respecto a la función process.nextTick de Node.js (que pone en cola las microtasks ), existe 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 microtask después de que se alcanza este límite, lo que permite procesar la próxima macrotask )
Entonces, ¿cuándo usar qué?
Básicamente, use microtasks cuando necesite hacer cosas de forma asíncrona de forma sincrónica (es decir, cuando diría que realice esta (micro) tarea en el futuro más inmediato ). De lo contrario, se adhieren a macrotasks .
Ejemplos
macrotasks:
setTimeout, setInterval, setImmediate, requestAnimationFrame, I / O, UI rendering
microtasks:
process.nextTick, Promises, Object.observe, MutationObserver