Microtâche en JavaScript : la file prioritaire des promesses

Une microtâche s'exécute avant la prochaine tâche de la boucle d'événements : ce qui en crée, l'ordre garanti, et comment on affame la boucle.
3 min de lecture
Believemy logo

Deux callbacks inscrits l'un après l'autre ne passent pas forcément dans cet ordre. Celui d'une promesse devance celui d'un minuteur, même écrit après lui.

La raison tient à une file distincte, servie en priorité par la boucle d'événements, et dont l'existence explique la plupart des ordres d'exécution surprenants.

Les deux files de la boucle et leur ordre de passageLes trois microtâches de la file passent les unes après les autres, et la première tâche n'est reprise qu'ensuite.Les microtâches passent toutes avant la première tâcheLe temps va vers la droiteFile des microtâchesservie jusqu'au boutqueueMicrotaskthenawaitToute la file passe d'abord, sans interruptionFile des tâchesune seule par toursetTimeoutLa tâche n'entre qu'une fois la file videUne microtâche qui en ajoute une reste dans le même tour


Définition

Une microtâche est un travail court placé dans une file servie intégralement dès que la pile d'appels se vide, avant que la moindre tâche ordinaire ne soit reprise. Trois choses en produisent.

  • Un then(), un catch ou un finally sur une promesse déjà réglée ou qui vient de l'être.
  • La reprise après un await, qui est exactement la même mécanique écrite autrement.
  • Un appel à queueMicrotask, la façon explicite d'en inscrire une.
JAVASCRIPT
setTimeout(() => console.log("tâche"), 0);
queueMicrotask(() => console.log("microtâche"));
Promise.resolve().then(() => console.log("promesse"));
console.log("synchrone");

// synchrone
// microtâche
// promesse
// tâche


Microtâche et tâche : la différence qui compte

CritèreMicrotâcheTâche
OriginePromesses, queueMicrotaskMinuteurs, événements, requêtes
Nombre par tourToute la file, sans interruptionUne seule, puis la boucle repasse
Rendu de la pageAucun avant la fin de la filePossible entre deux tâches

Ces trois lignes expliquent le comportement observé : la file des microtâches est vidée d'un bloc, et une microtâche qui en inscrit une autre allonge le même tour au lieu d'attendre le suivant.


Affamer la boucle

Cette priorité a un prix. Une microtâche qui s'inscrit elle-même sans condition d'arrêt occupe la file indéfiniment : les minuteurs ne se déclenchent plus, les clics ne sont plus traités, et la page se fige sans qu'aucune boucle infinie n'apparaisse dans le code.

JAVASCRIPT
// À ne pas exécuter : la boucle d'événements ne reprend jamais la main
// function boucler() { queueMicrotask(boucler); }
// boucler();

// La version correcte, qui laisse respirer la boucle
function bouclerProprement(reste) {
  if (reste === 0) return console.log("terminé");
  setTimeout(() => bouclerProprement(reste - 1), 0);
}

bouclerProprement(3);
Bon à savoir

Une récursion écrite avec await a le même défaut si rien ne rend la main : chaque reprise est une microtâche. Insérer une attente réelle, même d'une milliseconde, suffit à repasser par la file des tâches et à débloquer l'interface.


Questions fréquentes

Question

Pourquoi préférer queueMicrotask à setTimeout(fn, 0) ?

Parce que la microtâche s'exécute avant tout rendu et avant toute autre tâche, ce qui garantit qu'aucun état intermédiaire n'est visible. setTimeout laisse au contraire la page se rafraîchir entre-temps, ce qui est parfois exactement ce que l'on veut.


Question

L'ordre entre deux microtâches est-il garanti ?

Oui, la file est strictement premier entré, premier sorti. Deux then posés sur des promesses déjà tenues s'exécutent dans l'ordre d'inscription. C'est cette garantie qui rend le comportement des promesses reproductible d'une exécution à l'autre.


Question

Faut-il connaître ce détail pour écrire du code correct ?

Pas au quotidien, mais il devient indispensable dès qu'un ordre inattendu apparaît, notamment dans les tests : une assertion écrite juste après un appel asynchrone s'exécute avant la reprise de celui-ci. Comprendre la file explique alors l'écart en quelques secondes.

Termes connexes

Découvrez notre glossaire JavaScript

Tous les mots de JavaScript expliqués simplement : mots-clés, objets natifs, méthodes, erreurs et concepts. Définitions claires et exemples qui tournent, pour apprendre et pour se dépanner.

Partager cet article

Tu veux nous aider ? Fais un lien vers cet article sur tes réseaux ou encore mieux : sur ton site, dans un article ou dans ta newsletter.