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】
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:
Promise
,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:
Dans votre exemple:
new Promise
Et resolve
sont synchrones;setTimeout
dans la file d'attente des macrotâches;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
;setTimeout
à la file d'attente macrotask;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
setTimeout
à la file d'attente de macrotask, et une microtask promise.then()
à la file d'attente de microtask;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.