web-dev-qa-db-ja.com

イベントループとプロミスの関係は何ですか

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の関係に重点を置いているためです)

13
PageYe

各イベントループには、マイクロタスクキューとマクロタスクキューがあります。

マイクロタスクは、タスクキューではなく、マイクロタスクキューにキューイングされるタスクです。 https://www.w3.org/TR/html51/webappapis.html#microtask-queue を参照してください。

マイクロタスクには2種類あります。

  • Promiseなどの単独のコールバックマイクロタスク
  • node.jsの_Object.observe_、MutationObserver、_process.nextTick_などの複合マイクロタスク。

そして、マクロタスクキューは主にNodejsでsetTimeoutsetIntervalsetImmediaterequestAnimationFrame、_I/O_を含みます。

イベントループでは、これらの2つのタスクキューは2つのステップで実行されます。

  1. まず、古いマクロタスクキューにマクロタスク(Xと呼ばれます)があるかどうかを確認します。
  2. Xが存在し、実行中の場合は、Xが完了するまで次のステップに進むのを待ちます。それ以外の場合は、すぐに次のステップに進みます。
  3. 次に、マイクロタスクキューのすべてのマイクロタスクを実行します。
  4. マイクロタスクを実行すると、さらにいくつかのマイクロタスクをキューに追加できます。これらのタスクも実行されます。

あなたの例では:

  1. まず、Promiseの初期化_new Promise_とresolveは同期しています。
  2. 次に、setTimeout macroTaskをマクロタスクキューに同期的に追加します。
  3. 次に、マイクロタスクpromise.then(function(){})をマイクロタスクキューに同期的に追加します。このタスクは即座に実行されます。これは、Promiseの初期化と解決が同期しているため、このタスクがマクロタスクの前に実行されるためです。したがって、console.log __p1 fulfilled_;
  4. 次に、2番目のマクロタスクsetTimeoutをマクロタスクキューに追加します。
  5. このイベントループが終了した後、2つのマクロタスクを実行します。

このコードの場合:

_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
_
  1. 最初に3つのマクロタスクsetTimeoutをマクロタスクキューに追加し、マイクロタスクpromise.then()をマイクロタスクキューに追加します。
  2. マクロタスクを実行します。
  3. 条件がtrueの場合、すべてのマイクロタスクが実行されますが、falseの場合、次のステップに進みます。
  4. 2番目のマクロタスクを実行します。
  5. promiseが解決されたかどうかを確認し、条件がtrueの場合、すべてのマイクロタスクを実行します。
  6. 他のマクロタスクを実行します。
19
JiangangXiong

スタックがDr. Axel Rauschmayer here に従ってアプリケーションコードをクリアしない限り、Promiseは呼び出されません。

... Promises/A +仕様では、後者の実行モードを常に使用することが要求されています。それは、then()メソッドの次の requirement (2.2.4)を介してそう述べています。

onFulfilledまたはonRejectedは、実行コンテキストスタックにプラットフォームコードのみが含まれるまで呼び出さないでください。

注意することが重要です:

つまり、コードは実行から完了までのセマンティクス(パート1で説明したとおり)に依存する可能性があり、プロミスをチェーンしても他の処理時間のタスクが不足することはありません。

0
sheeldotme