2016-03-19 16 views
3

マシン(ノード5.8.0がインストールされている)でコードサンプルを実行し、次の結果を得る(コードサンプルの後を参照)。Promise.all(配列)がすぐに解決されないのはなぜですか?

コードサンプル:

'use strict' 

var p1 = Promise.resolve(); 
var p2 = Promise.resolve(); 

var p12 = Promise.all([p1, p2]); 

var cb = function() { 
    console.log(p12); 
} 

setTimeout(cb, 0); 

console.log(p1); 
console.log(p2); 
console.log(p12); 

結果:

プロミス{不定}
プロミス{不定}
プロミス{<pending>}
プロミス{[不定、不定]}

なぜp12がp1とp2の直後に解決されないのですか(プログラムの開始時にp1とp1が解決される)、なぜ 'タイムアウトしました' p12が解決されたのですか? Promise.all(配列)が解決されるのに少し時間が必要ですか?

+0

「Promise.resolve(true);」 – CodingGorilla

答えて

4

約束の仕様によれば、約束または拒否ハンドラは、イベントループが現在のサイクルを終了した後、常に非同期に呼び出されます。したがって、p12は、引数がすべての約束を解決してもすぐには解決されません。したがって、このイベントループが終了した直後に解決されることはありません。これは、あなたの最初の声明がなぜなぜ「保留中」であるかを示す理由を説明しています:

console.log(p12); 

現在の.then()ハンドラ(もしあれば)がまだ呼び出されていません。しかし、コードの現在のスレッドが実行を終了し、制御がイベントキューの次のイベントに戻ると、約束が解決されるため、setTimeout()はそれまでに解決したとみなします。 .then()ハンドラが約束はすでに解決されたか、まだ解決されていないかどうかに関係なく、非同期的に一貫して呼ばれていないよう


これは、呼び出し元の一貫性の理由のために行われます。これにより、約束がすでに解決されているかどうかを心配することなく、呼び出しコードを常に一貫してコード化することができます。すべての場合、現在のスタックが巻き戻されて終了した後にハンドラが呼び出されます。.then()Promises/A+ specificationから

:実行 コンテキストスタックが唯一のプラットフォームのコードを含むまで

がonFulfilledまたはonRejectedが呼び出されてはいけません。

ここで「プラットフォームコード」とは、エンジン、環境、約束コード を意味します。実際には、この要件は、 onFulfilledとonRejectedが、 というイベントが呼び出された後、新しいスタックで非同期に実行されるようにします。これは、 のsetTimeoutや setImmediateなどの「マクロタスク」メカニズム、または MutationObserverやprocess.nextTickなどの「マイクロタスク」メカニズムで実装できます。約束実施 はプラットフォームコードと見なされるので、ハンドラが呼び出されるタスクスケジューリング キューまたは「トランポリン」をそれ自体が含んでもよい。

これは、現在の実行スレッドが終了した後も常に約束が非同期に解決されることを示しています。内部の詳細はこれより少し複雑かもしれませんが(おそらくマイクロタスクが関与しています)、解決/拒否を待っているメッセージをイベントキューにポストすることによって、論理的に解決できると考えることができます。また、イベントキューが現在実行中のものを終了し、約束を実行するようになると、.then()ハンドラが実行されます。

+0

".all(配列)"は ".then()"ハンドラ( ".resolve()"メソッドと同じように理解する必要があります) ...意味がある。ありがとう。 @ jfriend00 – olegzhermal

関連する問題