web-dev-qa-db-fra.com

Différence entre microtask et macrotask dans un contexte de boucle d'événement

Je viens de terminer la lecture de la spécification Promises/A + et je suis tombé sur les termes microtask et macrotask: voir http://promisesaplus.com/#notes

Je n'ai jamais entendu parler de ces termes auparavant, et maintenant je suis curieux de savoir quelle pourrait être la différence?

J'ai déjà essayé de trouver des informations sur le Web, mais tout ce que j'ai trouvé est ce billet des archives de w3.org (qui ne m'explique pas la différence): http: //lists.w3 .org/Archives/Public/public-nextweb/2013Jul/0018.html

De plus, j'ai trouvé un module npm appelé "macrotask": https://www.npmjs.org/package/macrotask Encore une fois, la différence n'est pas clairement définie.

Tout ce que je sais, c'est que cela a quelque chose à voir avec la boucle d'événement, comme décrit dans https://html.spec.whatwg.org/multipage/webappapis.html#task-queue et - https://html.spec.whatwg.org/multipage/webappapis.html#perform-a-microtask-checkpoint

Je sais que je devrais théoriquement pouvoir extraire moi-même les différences, compte tenu de cette spécification WHATWG. Mais je suis sûr que d’autres pourraient également bénéficier d’une brève explication donnée par un expert.

112
NicBright

Un tour de la boucle d'événement aura exactement un tâche en cours de traitement à partir de la file d'attente macrotask (cette file d'attente est simplement appelée la file d'attente de tâches = dans le spécification WHATWG ). Une fois ce macrotask terminé, tous les microtasks disponibles seront traités, à savoir dans le même cycle de remise des gaz. Pendant que ces microtaches sont traitées, elles peuvent mettre en file d’attente encore plus de microtasks, qui seront toutes exécutées une par une, jusqu’à épuisement de la file d’attente de microtaches.

Quelles sont les conséquences pratiques de cela?

Si un microtask met automatiquement en file d'attente d'autres microtaches, le traitement du macrotask suivant peut prendre beaucoup de temps. Cela signifie que vous risquez de vous retrouver avec une interface utilisateur bloquée ou une activité inactive terminée dans votre application.

Cependant, du moins en ce qui concerne la fonction process.nextTick de Node.js (qui met en file d'attente microtasks), il existe une protection intégrée contre ce blocage par le biais de process.maxTickDepth. Cette valeur est définie sur une valeur par défaut de 1000, réduisant ainsi le traitement ultérieur de microtasks une fois cette limite atteinte, ce qui permet de traiter le prochain [macrotask)

Alors, quand utiliser quoi?

Fondamentalement, utilisez microtasks lorsque vous devez exécuter des tâches de manière synchrone de manière asynchrone (c.-à-d. Lorsque vous dites effectuez cette (micro-) tâche dans un avenir très immédiat) . Sinon, respectez macrotasks.

Exemples

macrotasks: setTimeout, setInterval, setImmediate, requestAnimationFrame, E/S, rendu de l'interface utilisateur
microtasks: process.nextTick, Promises, Object.observe, MutationObserver

174
NicBright

J'ai écrit un article à ce sujet, comprenant des exemples interactifs https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/

Mise à jour: j'ai également donné une conférence à ce sujet https://www.youtube.com/watch?v=cCOL7MC4Pl . La discussion va plus en détail, y compris la façon dont les tâches et les micro-tâches interagissent avec le rendu.

72
JaffaTheCake

Concepts de base en spec :

  • Une boucle d'événement a une ou plusieurs files d'attente de tâches (la file d'attente de tâches est la file d'attente macrotask).
  • Chaque boucle d'événement a une file d'attente de microtaches.
  • file d'attente = file d'attente macrotask! = file d'attente microtask
  • une tâche peut être insérée dans une file d'attente macrotask ou une file d'attente microtask
  • lorsqu'une tâche est placée dans une file d'attente (micro/macro), cela signifie que la préparation du travail est terminée. La tâche peut donc être exécutée maintenant.

Et le modèle de processus de boucle d'événement est le suivant:

lorsque pile d'appels est vide, effectuez les étapes suivantes:

  1. sélectionner la tâche la plus ancienne (tâche A) dans les files d'attente
  2. si la tâche A est nulle (signifie que les files d'attente de tâches sont vides), passez à l'étape 6
  3. définir "tâche en cours d'exécution" sur "tâche A"
  4. lancer "tâche A" (signifie exécuter la fonction de rappel)
  5. définir "tâche en cours d'exécution" sur null, supprimer "tâche A"
  6. effectuer une file d'attente de microtaches
    • (a) .sélectionnez la tâche la plus ancienne (tâche x) dans la file d'attente des microtaches
    • (b) .si la tâche x est nulle (signifie que les files d'attente de microtaches sont vides), passez à l'étape (g)
    • (c) .set "tâche en cours d'exécution" à "tâche x"
    • (d) .run "tâche x"
    • (e) .set "tâche en cours d'exécution" sur null, supprime "tâche x"
    • (f) .sélectionnez la tâche la plus ancienne suivante dans la file d'attente des microtaches, passez à l'étape (b)
    • (g) .finish microtask queue;
  7. sauter à l'étape 1.

un modèle de processus simplifié est le suivant:

  1. exécutez la tâche la plus ancienne de la file d'attente macrotask, puis supprimez-la.
  2. exécutez toutes les tâches disponibles dans la file d'attente de microtaches, puis supprimez-les.
  3. tour suivant: exécuter la tâche suivante dans la file d'attente des macrotask (étape 2 du saut)

quelque chose dont il faut se souvenir:

  1. lorsqu'une tâche (dans la file d'attente macrotask) est en cours d'exécution, de nouveaux événements peuvent être enregistrés. Ainsi, de nouvelles tâches peuvent être créées. Voici deux nouvelles tâches créées:
    • le rappel de promiseA.then () est une tâche
      • promiseA est résolue/rejetée: la tâche sera placée dans la file d'attente des microtaches dans le cycle actuel de la boucle d'événements.
      • promiseA est en attente: la tâche sera placée dans la file d'attente des microtaches dans la prochaine série de boucles d'événements (peut être la prochaine série)
    • le rappel de setTimeout (callback, n) est une tâche et sera poussé dans la file d'attente macrotask, même si n est égal à 0;
  2. la tâche dans la file d'attente microtask sera exécutée dans le tour en cours, tandis que la tâche dans la file d'attente macrotask doit attendre le tour suivant de la boucle d'événement.
  3. nous savons tous que les rappels de "click", "scroll", "ajax", "setTimeout" ... sont des tâches, mais nous devons également nous rappeler que les codes js dans leur ensemble dans le script sont également une tâche (un macrotask).
40
wengeezhang