ホームページ > 記事 > ウェブフロントエンド > この記事では、ノード イベント ループのタイマー キューについて説明します。
前の記事では、マイクロタスク キューと各キュー内の優先順位について説明しました。この記事では、非同期コードを処理するための Node.js の別のキューであるタイマー キューについて説明します。
タイマー キューについて詳しく説明する前に、マイクロタスク キューについて簡単に見てみましょう。コールバック関数をマイクロタスク キューにエンキューするには、process.nextTick()
や Promise.resolve()
などの関数を使用します。 Node.js で非同期コードを実行する場合、マイクロタスク キューの優先順位が最も高くなります。 [関連チュートリアルの推奨事項: nodejs ビデオ チュートリアル 、プログラミング教育 ]
次に、タイマーに進みます。列。コールバック関数をタイマー キューに入れるには、setTimeout
や setInterval
などの関数を使用できます。説明の便宜上、この記事では setTimeout
を使用します。
タイマー キューの実行順序を理解するために、マイクロタスク キューとタイマー キューにタスクをエンキューする一連の実験を実行します。
// index.js setTimeout(() => console.log("this is setTimeout 1"), 0); setTimeout(() => console.log("this is setTimeout 2"), 0); setTimeout(() => console.log("this is setTimeout 3"), 0); process.nextTick(() => console.log("this is process.nextTick 1")); process.nextTick(() => { console.log("this is process.nextTick 2"); process.nextTick(() => console.log("this is the inner next tick inside next tick") ); }); process.nextTick(() => console.log("this is process.nextTick 3")); Promise.resolve().then(() => console.log("this is Promise.resolve 1")); Promise.resolve().then(() => { console.log("this is Promise.resolve 2"); process.nextTick(() => console.log("this is the inner next tick inside Promise then block") ); }); Promise.resolve().then(() => console.log("this is Promise.resolve 3"));
翻訳注: 緊張しないでください。このコードは次のとおりです。前回の記事 「福祉実験」を元に、先頭に
setTimeout
ステートメントを 3 つ追加しました。
このコードには、3 つの process.nextTick()
呼び出し、3 つの Promise.resolve()
呼び出し、および 3 つの setTimeout
呼び出しが含まれています。各コールバック関数は、適切なメッセージをログに記録します。 3 つの setTimeout
呼び出しにはすべて 0ms
の遅延があります。つまり、各 setTimeout
ステートメントが実行されると、コールバック関数はすぐにタイマー キューに登録されて待機します。 . . 2 番目の process.nextTick()
と 2 番目の Promise.resolve()
には追加の process.nextTick()
ステートメントがあり、それぞれにコールバック関数があります。 。
#コール スタックがすべてのステートメントを実行すると、nextTick キューに 3 つのコールバックが存在し、次のキューに 3 つのコールバックが存在します。 Promise キュー。3 つのコールバック。タイマー キューにも 3 つのコールバックがあります。実行するコードはなく、制御はイベント ループに渡されます。
nextTick キューの優先順位が最も高く、次に Promise キュー、タイマー キューの順です。 nextTick キューから最初のコールバックを取得して実行し、メッセージをコンソールに記録します。次に、2 番目のコールバックを取得して実行します。これにより、メッセージも記録されます。 2 番目のコールバックには、process.nextTick()
への呼び出しが含まれており、新しいコールバックを nextTick キューに追加します。実行を続行し、3 番目のコールバックを取得して実行し、メッセージをログに記録します。最後に、nextTick キューに新しく追加されたコールバック関数を取り出してコール スタックで実行し、コンソールに 4 番目のログ メッセージを出力します。
nextTick キューが空の場合、イベント ループは Promise キューに変わります。キューから最初のコールバックを取得し、コンソールにメッセージを出力します。2 番目のコールバックにも同様の効果があり、nextTick キューにコールバックを追加します。 Promise の 3 番目のコールバックが実行され、ログ メッセージが出力されます。この時点では、Promise キューは空であり、イベント ループは nextTick キューをチェックして新しいコールバックがあるかどうかを確認し、見つかったメッセージはコンソールにも記録されます。
これで、両方のマイクロタスク キューが空になり、イベント ループがタイマー キューに変わります。 3 つのコールバックがあり、それぞれがタイマー キューから取得されてコール スタック上で実行され、それぞれ「setTimeout 1」、「setTimeout 2」、および「setTimeout 3」を出力します。
this is process.nextTick 1 this is process.nextTick 2 this is process.nextTick 3 this is the inner next tick inside next tick this is Promise.resolve 1 this is Promise.resolve 2 this is Promise.resolve 3 this is the inner next tick inside Promise then block this is setTimeout 1 this is setTimeout 2 this is setTimeout 3
マイクロタスク キューのコールバック関数は、タイマー キューのコールバック関数より前に実行されます。
これまでの優先順位は、nextTick キュー、Promise キュー、タイマー キューの順です。では、次の実験に進みましょう。
// index.js setTimeout(() => console.log("this is setTimeout 1"), 0); setTimeout(() => { console.log("this is setTimeout 2"); process.nextTick(() => console.log("this is inner nextTick inside setTimeout") ); }, 0); setTimeout(() => console.log("this is setTimeout 3"), 0); process.nextTick(() => console.log("this is process.nextTick 1")); process.nextTick(() => { console.log("this is process.nextTick 2"); process.nextTick(() => console.log("this is the inner next tick inside next tick") ); }); process.nextTick(() => console.log("this is process.nextTick 3")); Promise.resolve().then(() => console.log("this is Promise.resolve 1")); Promise.resolve().then(() => { console.log("this is Promise.resolve 2"); process.nextTick(() => console.log("this is the inner next tick inside Promise then block") ); }); Promise.resolve().then(() => console.log("this is Promise.resolve 3"));
4 番目の実験のコードは 3 番目の実験とほとんど同じですが、1 つの例外があります。 2 番目の setTimeout
関数に渡されるコールバック関数には、process.nextTick()
への呼び出しが含まれています。 #########視覚化###############
让我们应用从之前的实验中学到的知识,快进到回调在微任务队列中已经被执行的点。假设我们有三个回调在计时器队列中排队等待。第一个回调出队并在调用堆栈上执行,“setTimeout 1”消息打印到控制台。事件循环继续运行第二个回调,“setTimeout 2”消息打印到控制台。同时,也会有一个回调函数入队了 nextTick 队列。
在执行计时器队列中的每个回调后,事件循环会返回检查微任务队列。检查 nextTick 队列确定需要执行的回调函数。这时第二个 setTimeout
推入的回调函数出队并在调用栈上执行,结果“inner nextTick”消息打印到控制台。
现在微任务队列为空了,控制权返回到计时器队列,最后一个回调被执行,控制台上显示消息“setTimeout 3”。
this is process.nextTick 1 this is process.nextTick 2 this is process.nextTick 3 this is the inner next tick inside next tick this is Promise.resolve 1 this is Promise.resolve 2 this is Promise.resolve 3 this is the inner next tick inside Promise then block this is setTimeout 1 this is setTimeout 2 this is inner nextTick inside setTimeout this is setTimeout 3
微任务队列中的回调函数会在定时器队列中的回调函数执行之间被执行。
// index.js setTimeout(() => console.log("this is setTimeout 1"), 1000); setTimeout(() => console.log("this is setTimeout 2"), 500); setTimeout(() => console.log("this is setTimeout 3"), 0);
该代码包含三个 setTimeout
语句,包含三个不同的、入队时机不一样的回调函数。第一个 setTimeout
延迟 1000 毫秒,第二个延迟 500 毫秒,第三个延迟 0 毫秒。当执行这些回调函数时,它们只是简单地将一条消息记录到控制台中。
由于代码片段的执行非常简单,因此我们将跳过可视化实验。当多个 setTimeout
调用被发出时,事件循环首先排队最短延迟的一个并在其他之前执行。结果,我们观察到“setTimeout 3”先执行,然后是“setTimeout 2”,最后是“setTimeout 1”。
this is setTimeout 3 this is setTimeout 2 this is setTimeout 1
计时器队列回调按照先进先出(FIFO)的顺序执行。
实验表明,微任务队列中的回调比定时器队列中的回调具有更高优先级,并且微任务队列中的回调在定时器队列中的回调之间执行。定时器队列遵循先进先出(FIFO)顺序。
原文链接:Visualizing The Timer Queue in Node.js Event Loop,2023年4月4日,by Vishwas Gopinath
更多node相关知识,请访问:nodejs 教程!
以上がこの記事では、ノード イベント ループのタイマー キューについて説明します。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。