Event LoopとPromiseの関係に興味があります。
デモは問題を明らかにします。 p1 fulfilled
が真ん中に表示されると思いましたが、 同じタスクキューにタスクをキューイングし、1つずつ実行されるためです。
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)
コンソールの結果は次のとおりです。
p1 fulfilled
will be executed at the top of the next Event Loop
will be executed at the bottom of the next Event Loop
視覚化された効果 は、promise.then
のコールバックがイベントループのタスクキューに移動しなかったことを示しています。それはそうです?
【注:質問は Promise vs setTimeout と同じではありません。イベントループとPromiseの関係に重点を置いているためです)
各イベントループには、マイクロタスクキューとマクロタスクキューがあります。
マイクロタスクは、タスクキューではなく、マイクロタスクキューにキューイングされるタスクです。 https://www.w3.org/TR/html51/webappapis.html#microtask-queue を参照してください。
マイクロタスクには2種類あります。
Promise
などの単独のコールバックマイクロタスクObject.observe
_、MutationObserver
、_process.nextTick
_などの複合マイクロタスク。そして、マクロタスクキューは主にNodejsでsetTimeout
、setInterval
、setImmediate
、requestAnimationFrame
、_I/O
_を含みます。
イベントループでは、これらの2つのタスクキューは2つのステップで実行されます。
あなたの例では:
new Promise
_とresolve
は同期しています。setTimeout
macroTaskをマクロタスクキューに同期的に追加します。promise.then(function(){})
をマイクロタスクキューに同期的に追加します。このタスクは即座に実行されます。これは、Promiseの初期化と解決が同期しているため、このタスクがマクロタスクの前に実行されるためです。したがって、console.log __p1 fulfilled
_;setTimeout
をマクロタスクキューに追加します。このコードの場合:
_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)
}
_
出力順序:
_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
をマクロタスクキューに追加し、マイクロタスクpromise.then()
をマイクロタスクキューに追加します。スタックがDr. Axel Rauschmayer here に従ってアプリケーションコードをクリアしない限り、Promiseは呼び出されません。
... Promises/A +仕様では、後者の実行モードを常に使用することが要求されています。それは、then()メソッドの次の requirement (2.2.4)を介してそう述べています。
onFulfilledまたはonRejectedは、実行コンテキストスタックにプラットフォームコードのみが含まれるまで呼び出さないでください。
注意することが重要です:
つまり、コードは実行から完了までのセマンティクス(パート1で説明したとおり)に依存する可能性があり、プロミスをチェーンしても他の処理時間のタスクが不足することはありません。