promise、process.nextTick、set Timeoutから出発して、Event LoopのJob queueを話します.
一、問題の引き出しイベントloopとは、メインスレッドが「ジョブキュー」からループ読み出しタスク を意味する.
例1: JavaScriptは、単一スレッドで実行されています.つまり、複数のコードを同時に実行することはできません.あるコードが実行されている場合、後続のすべてのタスクは待ち時間が必要です.現在のタスクが実行されたら、次のタスクをキューから取り出します.これはしばしば「閉塞式執行」と呼ばれる. マウスを一回クリックしたり、タイマーが到着したり、Ajax要求が完了したら、コールバック関数が起動されます.これらのイベントハンドラやコールバック関数はすぐに実行されないです.すぐにキューに並べば、スレッドが空き次第に実行されます. 現在JavaScriptプロセスが実行中である場合、マウスクリックが発生した場合、イベントハンドラがブロックされ、ユーザもすぐにフィードバックを見ることができなくなり、イベントハンドラは前のコードが終わってから実行を開始するまで、タスクキューに入れられます.コードにsetTimeoutが設定されている場合、ブラウザは適切な時間にコードをタスクキューに挿入します.この時間を0にすると、直ちにキューに挿入することを表しますが、すぐに実行するのではなく、前のコードの実行が完了するまで待ちます. setTimeoutは実行時間が保証されていません.JavaScriptスレッドが混雑しているかそれともアイドル状態なのかによって、タイムリーに実行されるかは保証されていません. event loop読み出しジョブの先着順は、ジョブキュー(Job queue)における異なるジョブ読取規則に対する制限 に依存する.
例2:
二、Job queueの実行順序 Job queueにおけるキューは2つのタイプに分けられています.macro-taskとmicroTask 例えば、実行順序の規定を見ると、設定:macro-taskキューはタスクを含む:a 1,a 2,a 3 micro-taskキューはタスクを含む:b 1,b 2,b 3
実行順序は、まずマルコ-taskキューの先頭のタスク、つまりa 1タスクを実行し、実行が終わったら、micro-taskキューの中のすべてのタスクを実行します.つまり、b 1,b 2,b 3を順次実行します.実行が終わったら、micro-taskの中のタスクをクリアし、次にマルコ-taskの中の第二のタスクを実行して、順次循環します.は、macro-taskとmicro-taskの2つの列の実行順序を把握した後、リアルなシーンの下でこれらの2つのタイプのキューに本当に含まれるタスク(node V 8エンジンの例)を見に行く .
node V 8において、これらの2つのタイプの真のタスク順序は以下の通りである. macro-taskキューは本当にタスクを含みます. micro-taskキューは本当にタスクを含みます. によって得られた実行順序は、 であるべきである. ES 6におけるmacro-taskの列はScript Jobsとも呼ばれ、micro-taskはPromiseJobs とも呼ばれています.
三、実際の環境における実行順序の例
例3:setTimeoutとpromise
例4:process.nextTickとpromise、setTimeout
まずJob queueの実行順序を分析します.
II)process.nextTick:出力5
III)promise:ここのpromiseの部分は、厳密にはpromise.thenの部分で、出力は3,4です.
IV)setTimeout:最終出力1
総合的な実行順序:2——>>6——>5——>>3——>4——>1
例5:より複雑な例
例1:
setTimeout(
function(){
console.log(1);
}
},0);
console.log(2);
// 2,1
上記の例では、まずメインスレッドにおける同期タスクを実行し、メインスレッドタスクの実行が完了したら、イベントloopからタスクを読み出すので、先に2を出力してから1を出力します.例2:
setTimeout(function () {
console.log(3);
}, 0);
Promise.resolve().then(function () {
console.log(2);
});
console.log(1);
// 1 2 3
先に1を出力するのは、同期タスクがメインスレッド内で優先的に実行されるからですが、ここでの問題は、setTimeoutとPromise.thenタスクの実行優先度がどのように定義されていますか?二、Job queueの実行順序
実行順序は、まずマルコ-taskキューの先頭のタスク、つまりa 1タスクを実行し、実行が終わったら、micro-taskキューの中のすべてのタスクを実行します.つまり、b 1,b 2,b 3を順次実行します.実行が終わったら、micro-taskの中のタスクをクリアし、次にマルコ-taskの中の第二のタスクを実行して、順次循環します.
node V 8において、これらの2つのタイプの真のタスク順序は以下の通りである.
script( ),setTimeout, setInterval, setImmediate, I/O, UI rendering
process.nextTick, Promises, Object.observe, MutationObserver
script( )—>process.nextTick—>Promises...——>setTimeout——>setInterval——>setImmediate——> I/O——>UI rendering
三、実際の環境における実行順序の例
例3:setTimeoutとpromise
setTimeout(function () {
console.log(3);
}, 0);
Promise.resolve().then(function () {
console.log(2);
});
console.log(1);
まず第1小節の例を例にとって、ここで従う順序は以下の通りである.script( )——>promise——>setTimeout
対応する出力は、順次:1——>>2——>3例4:process.nextTickとpromise、setTimeout
setTimeout(function(){console.log(1)},0);
new Promise(function(resolve,reject){
console.log(2);
resolve();
}).then(function(){console.log(3)
}).then(function(){console.log(4)});
process.nextTick(function(){console.log(5)});
console.log(6);
// 2,6,5,3,4,1
promiseを定義する際に、promise構造部分は同期して実行されます.まずJob queueの実行順序を分析します.
script( )——>process.nextTick——>promise——>setTimeout
I)本体部:promiseを定義する構造部分は同期しているので、まず2を出力し、本体部分は更に6を出力する(同期の場合は、厳密に定義された順序に従う)II)process.nextTick:出力5
III)promise:ここのpromiseの部分は、厳密にはpromise.thenの部分で、出力は3,4です.
IV)setTimeout:最終出力1
総合的な実行順序:2——>>6——>5——>>3——>4——>1
例5:より複雑な例
setTimeout(function(){console.log(1)},0);
new Promise(function(resolve,reject){
console.log(2);
setTimeout(function(){resolve()},0)
}).then(function(){console.log(3)
}).then(function(){console.log(4)});
process.nextTick(function(){console.log(5)});
console.log(6);
// 2 6 5 1 3 4
例5と例4の違いはpromiseの構造において同期されていないresoveであるため、promise.thenは現在の実行列には存在せず、プロミセがpendingからresoveに移行してこそthen方法があり、このresoveはsetTimout時間で完成したので、3,4が最後に出力される.