web-dev-qa-db-fra.com

Quelle est la relation entre la boucle d'événements et Promise

Je suis curieux de connaître la relation entre Event Loop et Promise.
La démo expose la question. Je m'attendais à ce que p1 fulfilled Apparaisse au milieu, car ils mettent une tâche en file d'attente dans la même file d'attente de tâches et sont exécutés un par un.

var p1 = new Promise(function(resolve, reject){
    resolve(1)
})
setTimeout(function(){
  console.log("will be executed at the top of the next Event Loop")
},0)
p1.then(function(value){
  console.log("p1 fulfilled")
})
setTimeout(function(){
  console.log("will be executed at the bottom of the next Event Loop")
},0)

Le résultat de la console est:

p1 fulfilled
will be executed at the top of the next Event Loop
will be executed at the bottom of the next Event Loop

L'effet visualisé montre que le rappel du promise.then N'est pas allé dans la file d'attente des tâches de la boucle d'événements. C'est juste?

【REMARQUE: La question n'est pas la même que Promise vs setTimeout , car elle se concentre davantage sur la relation entre la boucle d'événement et la promesse】

13
PageYe

Chaque boucle d'événement a une file d'attente de microtâches et une file d'attente de macrotâches.

Une microtâche est une tâche qui doit à l'origine être mise en file d'attente dans la file d'attente de microtâche plutôt qu'une file d'attente de tâches. Reportez-vous à https://www.w3.org/TR/html51/webappapis.html#microtask-queue .

Il existe deux types de microtâches:

  • microtâches de rappel solitaire, telles que Promise
  • et des microtâches composées, telles que Object.observe, MutationObserver et process.nextTick dans Node.js.

Et la file d'attente macrotask contient principalement setTimeout, setInterval, setImmediate, requestAnimationFrame, I/O Dans Nodejs.

Dans une boucle d'événement, ces deux files d'attente de tâches s'exécuteront en deux étapes:

  1. Tout d'abord, vérifiez s'il y a une macrotask (appelée X) dans l'ancienne file d'attente de macrotask;
  2. Si X existe et qu'il est en cours d'exécution, attendez de passer à l'étape suivante jusqu'à ce qu'il soit terminé; sinon, passez immédiatement à l'étape suivante;
  3. Deuxièmement, exécutez tous les microtâches de la file d'attente des microtâches;
  4. et lorsque vous exécutez les microtâches, nous pouvons toujours ajouter quelques microtaks supplémentaires dans la file d'attente, ces tâches seront également exécutées.

Dans votre exemple:

  1. Tout d'abord, votre Promise initialize new Promise Et resolve sont synchrones;
  2. puis ajoutez de manière synchrone une macro-tâche setTimeout dans la file d'attente des macrotâches;
  3. puis ajoutez de façon synchrone la microtâche promise.then(function(){}) à la file d'attente des microtâches, cette tâche s'exécutera immédiatement, car l'initialisation et la résolution de la Promesse sont synchrones, cette tâche s'exécutant avant toute macrotâche; donc, console.log le p1 fulfilled;
  4. puis ajoutez la deuxième macrotask setTimeout à la file d'attente macrotask;
  5. une fois cette boucle d'événements terminée, exécutez les deux macrotâches;

pour ce code:

setTimeout(function(){
  console.log("will be executed at the top of the next Event Loop")
},0)
var p1 = new Promise(function(resolve, reject){
    setTimeout(function(){resolve(1)},0)
});
setTimeout(function(){
    console.log("will be executed at the bottom of the next Event Loop")
},0)
for (var i = 0; i < 100; i++) {
    (function(j){
        p1.then(function(value){
           console.log("promise then - " + j)
        });
    })(i)
}

l'ordre de sortie:

will be executed at the top of the next Event Loop
promise then - 0
promise then - 1
promise then - 2
...
promise then - 99
will be executed at the bottom of the next Event Loop
  1. Ajoutez d'abord trois macrotask setTimeout à la file d'attente de macrotask, et une microtask promise.then() à la file d'attente de microtask;
  2. exécuter une macrotask;
  3. Si la condition est vraie, exécutez tous les microtâches, mais c'est faux, alors passez à l'étape suivante;
  4. exécuter la deuxième macrotask;
  5. vérifier si la promesse a été résolue ou non, la condition est vraie, puis exécuter tous les microtâches;
  6. continuer à exécuter d'autres macrotasks;
19
JiangangXiong

Les promesses ne seront pas appelées sauf si la pile est exempte de code d'application selon Dr. Axel Rauschmayer ici .

... la spécification Promises/A + exige que ce dernier mode d'exécution soit toujours utilisé. Il le dit via la exigence (2.2.4) suivante pour la méthode then ():

onFulfilled ou onRejected ne doit pas être appelé tant que la pile de contexte d'exécution ne contient que du code de plate-forme.

Il est important de noter:

Cela signifie que votre code peut s'appuyer sur la sémantique de l'exécution jusqu'à la fin (comme expliqué dans la partie 1) et que les promesses de chaînage ne priveront pas d'autres tâches de temps de traitement.

0
sheeldotme