2016-11-30 4 views
7

次のコードの実行方法を理解できません。なぜ "1"は "b"の後に "h"は "3"の後にあるのですか?順序はa、b、1、2、h、3でなければならない?いくつかの記事は、 "イベントループキュー"と "ジョブキュー"の違いは、次の出力につながると述べています。しかしどうですか?私はECMAScript 2015 - 8.4 Jobs and Job Queuesの仕様を読んで、Promise'jobの仕組みを知りたいが、それはもっと混乱させる。誰か助けてくれますか?ありがとうございました!"イベントループキュー"と "ジョブキュー"の違いは何ですか?

var promise = new Promise(function(resolve, reject) {resolve(1)}); 
promise.then(function(resolve) {console.log(1)}); 
console.log('a'); 
promise.then(function(resolve) {console.log(2);}); 
setTimeout(function() {console.log('h')}, 0); 
promise.then(function(resolve) {console.log(3)}); 
console.log('b'); 

// a 
// b 
// 1 
// 2 
// 3 
// h 

私は約束が非同期である知っているが、setTimeoutメソッドのコールバック(..)非同期操作プロミスの非同期操作の後に常にあります。どうして?

+0

約束の非同期されている - 、.thenが非同期的に呼び出されるようにもインライン同期探しコード - それは約束が –

答えて

5

なぜ "1"が "b"の後に来るのですか?

約束通りに、.then()ハンドラは、現在のJSのスレッドが完了した後に非同期に呼び出されます。したがって、現在のJSの一部として同期して実行されるabの両方が.then()ハンドラの前に実行されるため、1は常にabの後になります。

興味深い読書:T asks, microtasks, queues and schedulesおよびWhat is the order of execution in javascript promisesおよびWriting a JavaScript framework - Execution timing, beyond setTimeout


このスレッドでは、ここでいくつか良いアドバイスがあります:Promises wiggle their way between nextTick and setImmediate

私は 非チェーンのイベントの正確な実行順序に依存することをお勧めしません。実行順序を制御する場合は、 コールバックを、後で実行する になるように並べ替えます。 を先に実行するか、キューを実装します(同じことを実行します)。フードの後ろに)。言い換えれば

あなたは非同期イベントの特定のタイミングに依存している場合、あなたは実際には、一方が他方の後に行われる必要がありますので、あなたのコードを介して、あなたのコードでそれらをそれらをチェーンではなく、実装に不特定のスケジューリングに頼る必要があります。

+1

を何だ、なぜ 'H'は、 '3'の後に 'です:p –

+0

@ JaromandaX、JS実装のジョブキューは、ブラウザによって実装されるイベントキューよりも高い優先順位を持つ可能性が最も高いです。しかし、本当にわからない。 – MinusFour

+0

@JaromandaX - それはOPが尋ねたものとは少し違う質問です。私は、それが仕様によるのか、 '.then()'ハンドラが '' setTimeout() ''イベントに対してキューに入れられたかに基づいて実装依存かどうかを調べるためにいくつかの研究をしなければなりません。 – jfriend00

3

HTMLでは、同じドメインのページまたはページセットのevent loopは複数のtask queuesを持つことができます。同じtask sourceのタスクは、常に同じキューに入り、ブラウザは次に使用するタスクキューを選択します。

タイマーコールバックを実行するタスクはtimer task sourceから来て、同じキューに入ります。このキューをタスクキュー "A"としましょう。

ECMAscript 2015(ES6)仕様では、プロミス反応コールバックを実行して"PromiseJobs"という独自のジョブキューを作成するタスクが必要です。 ECMAscriptとHTMLの仕様は同じ言語を使用していないので、ECMAの "Promise Job queue"とHTMLのタスクキュー "B"を考えてみましょう。少なくともタイマとは異なるキューです。

理論上、ブラウザは実行するキューAまたはBのいずれかからタスクを選択できますが、実際にはの約束タスクキューが優先され、タイマーコールバックが実行される前に空になります。

これが「h」が最後に記録される理由です。プロミスthenは、約束された約束を呼び出して、約束待ち行列にジョブを配置します。これは、タイマーコールバックよりも高い優先順位で実行されます。約束待ち行列は、console.log(3)が実行された後にのみ空になり、タイマーコールバックを実行することができます。


高度

ECMAScriptの保護者は、ECMAScriptのは、ちょうどHTMLブラウザよりも多くの環境で実行することができますので、その仕様でHTML5の用語やタスクキューの記述を使用しないことを選びました。

プロミスキューのネイティブ実装では、別個の専用プロミスタスクキューの代わりに「マイクロタスク」キューを使用できます。マイクロキューイングジョブは、現在のスクリプトスレッドとマイクロキューに以前に追加されたタスクの後に実行されます。

約束を理解するために、マイクロタスクキューイングの詳細は必要ありません。

プロミス(すべてのバージョンのIEなど)のネイティブサポートがないブラウザ用のPromiseポリフィルは、タイマーを使用する可能性があり、約束の反応やタイマーコールバックの順序についてネイティブ実装とまったく同じように動作しません。

0

私はこれをJSの新しい人には理解しやすいと感じました。

これは、@ getifyの本からコピーペーストである

メタファーを使用するには:イベントループキューを使用すると、乗り心地を終えた後、あなたがの裏に行かなければならアミューズメントパークの乗り物、のようなものです再び乗るためのライン。しかし、ジョブの待ち行列は乗り物を終えるのと同じですが、ラインを切ってすぐに戻ります。

イベントループキュー - 約束に関連するすべての非同期コールバック - 約束、時間

ジョブキュー以外のすべての非同期コールバック。 1、2、3

同期 - 、B

関連する問題