Nodeのイベントループ
Node の基盤となる言語は libuv で、v8 エンジンを使用して js スクリプトを解析します。
libuv はインターフェイス API を呼び出し、さまざまなタスクをさまざまなスレッドに渡して処理し、処理結果を v8 エンジンに渡し、v8 エンジンは処理結果をユーザーに送信します。
Node でのタスクの実行順序
- timers タイマー、並べたsetTimeoutとsetIntervalのコールバック関数を実行
- 保留中のコールバック: 次のループ反復まで実行が遅延される I/O コールバック
- アイドル、準備: システムによって内部的にのみ使用されます
- poll: 新しい I/O イベントを取得し、I/O 関連のコールバックを実行します。
- check: setImmedate() コールバック関数を実行する
- クローズド コールバック関数クローズ コールバック: たとえば、socket.on('close', ()=>{})
Node はオペレーティング システムを処理するため、
ブラウザのマクロ タスクがキューであるかどうかに関係なく、アイドル/準備/保留中のコールバックは Node の 6 つのマクロ タスク キューと見なすことができ、各キューは実行時に現在のキューをクリアします。 . キュー内のコールバック タスクは次のキューに移動します.
マイクロタスク: process.nextTick および Promise マイクロタスクを考慮すると、各キューが実行される前に、nextTick キューがクリアされてから Promise が実行されます.
process.nextTick > setImmediate > microtask
setImmediate と setTimeout(0) の実行順序直接実行すると、setTimeout(0) が最初に実行され、次に setImmediate が実行さ
れることがわかります。
オペレーティング システムの速度。setTimeout のプログラムは setImmediate よりも明らかに複雑で、タイマーを作成する必要があるため、setTimeout の実行イベントは setImmediate よりも長くなります。
console.log('start');
let timer1 = setTimeout(() => {
console.log(`settimeout 0`)
process.nextTick(() => {
console.log('settimeout process nextTick');
})
clearTimeout(timer1);
}, 0);
let timer2 = setTimeout(() => {
console.log(`settimeout 300`)
clearTimeout(timer2);
}, 300);
let interval = setInterval(() => {
console.log(`setInterval`)
clearInterval(interval);
}, 0);
process.nextTick(() => {
console.log('process nextTick');
})
const fs = require('fs')
fs.readFile('./test.js', () => {
console.log('poll');
setImmediate(() => {
console.log(`poll setImmediate`)
});
})
setImmediate(() => {
console.log(`setImmediate`);
});
new Promise(resolve => {
console.log('promise start');
resolve();
console.log('promise end');
}).then(() =>{
console.log('promise result');
})
console.log('end');
start
promise start
promise end
end
process nextTick
promise result
settimeout 0
setInterval
settimeout process nextTick
setImmediate
poll
poll setImmediate
settimeout 300
- 印刷開始
- timer1 はタイマー キューに参加します
- timer2 はタイマー キューに参加します
- インターバル ジョイン タイマー キュー
- すぐにチェック キューに参加します
- process.nextTick がマイクロタスク キューに参加します
- fs は I/O キューに参加します
- Promise の実行、Promise の開始、Promise の終了の出力 非同期マイクロタスク キューへのコールバックの追加
- 印刷スクリプト終了
- マイクロタスク キューを空にし始める
- promise.nextTick コールバックをクリアする
- promise コールバック キューをクリアする
- マクロタスク キューを空にし始める
- タイマーをクリアし、setTimeout(0) を実行し、マイクロタスク キューに process.nextTick を追加します。
- setTimeout(300) 時間が経過していないため、引き続きタイマーに配置され、実行されません
- setintervalexecution
- タイマー キューが空になりました。マイクロタスクを探します。ある場合は、process.nextTick を実行します。
- ポーリング キューを空にすることを開始します。この時点では、タスクを実行する時間ではありません。ポーリングは待機し、他のキューにタスクがあるかどうかを確認します。
- setImmediate コールバックが存在するため、ポーリングは待機します。まず、setImmediate の実行が完了するまで待機します。
- ポーリング キュー タスクの実行時間切れ、タスクのクリア、ポーリングの印刷、チェック キューへの setImmediate の追加
- チェック キューをクリアしてポーリングを印刷する setImmediate
- 1 サイクルが終了し、次のサイクルを開始する
- タイマー キューを空にし始める
- この時点で setTimeout(300) だけが残っています