ホームページ  >  記事  >  ウェブフロントエンド  >  この記事では、Node.js のイベントループについて理解します。

この記事では、Node.js のイベントループについて理解します。

青灯夜游
青灯夜游転載
2022-01-04 18:44:132250ブラウズ

メイン スレッドは「タスク キュー」からイベントを読み取ります。このプロセスは周期的であるため、実行メカニズム全体はイベント ループとも呼ばれます。次の記事は、Node.js のイベントループをマスターするのに役立ちます。お役に立てれば幸いです。

この記事では、Node.js のイベントループについて理解します。

#実はブラウザのイベントループについては前回の記事でもお話しました。ただし、NodeJs のイベントループはブラウザーのイベントループとは異なります。イベントループをマスターすることは、nodejs を作成する人々にとって非常に重要なスキルです。これは、jsを書くだけでなく、NodeJsの勉強もできることを意味するからです。

イベントループがあるのはなぜですか?

NodeJs の本質は、ブラウザーの v8 をオペレーティング システムで実行できるように移動することであるため、ブラウザーのイベント ループも引き継ぎます。しかし、なぜイベントループのようなデザインが登場するのでしょうか?

歴史的に見ると、js はページ上の dom を操作するための非常にシンプルな言語として設計されました (js がわずか 10 日で設計されたという話は誰もが聞いたことがあると思います)。この目標を達成するには、js の実行ができるだけシンプルで軽量であることが望ましいと考えています。 js と同じくらい軽いレンダリング エンジンがスレッドで実行されます。

次に問題が発生します。スレッド上で js を実行する場合、コードが線形であれば、もちろん問題はありません。しかし、ページ上ではユーザーとのインタラクションが必要ですが、これらのインタラクションはなぜ、いつ起こるのかわかりません。 jsをどう扱うか?目の前で実行中のコードがある場合、ユーザーが操作したときにプログラムはどのように反応するでしょうか?ユーザー対話が最初に処理されると、元のプログラムは一時停止 (つまり、ブロック) されます。この種のブロックを回避するために、js では、メッセージ キューを使用してこの種のユーザー インタラクションを保存する方法が採用されています。すべてのプログラムの実行が終了したら、メッセージ キューに移動して対話イベントを取得し、それを実行します。これにより、ブロッキングの問題が解決されます。

ブラウザ イベントループ

ブラウザがページを閲覧しているとき、ユーザーに即座に応答するために、いつでもユーザー インタラクションが発生する可能性があることは誰もが知っています。 js は閉じられず、ループし続けます。それはおおよそ次のとおりです:

向消息队列拿任务-->执行任务-->执行完毕--> 向消息队列拿任务--> ....

もちろん、さまざまな非同期タスクを分類するために、実際にはイベント ループ内でマクロ タスクとマイクロ タスクが区別されることは、前のイベント ループの記事で述べました。これらの実行はおおよそ

向消息队列拿微任务-->执行微任务-->微任务执行完毕--> 向消息队列拿宏任务-->执行宏任务-->宏任务执行完毕-->向消息队列拿微任务-->...

NodeJs のイベントループ

node のイベント ループはブラウザ上のイベント ループと実際には似ています。異なる時間に異なるマクロタスクを実行します。以下は公式のフローチャートです:

この記事では、Node.js のイベントループについて理解します。

nodeJs の各イベント ループが 6 つの特定の期間に分割されており、各期間が指定されたマクロ タスクを使用することがわかります。そして、各周期のマクロタスクが実行される前に、マイクロタスクキューが最初に実行されます。

#概要

タイマーsetTimeout()# によって実行## および #保留中のコールバックidle、preparepollcheckたとえば、
setInterval() トリガーされたコールバック
実行は、私が実行するまで遅延されます。次のループ反復の /O コールバック
は内部でのみ使用され、開発者は注意を払わない可能性があります
新しい I/O イベントを取得し、I/O 関連のコールバックを実行します (クローズ コールバックとタイマー スケジュールを除くほぼすべてのコールバックが実行されます) コールバックとコールバックsetImmediate() によってスケジュールされたものは、この段階で適切な時間にブロックされます)
Execution setImmediate() #コールバックを閉じる
socket.on('close', ...) #

其实通过上述表格,我们已经很清晰知道整个事件循环机制的执行顺序了。但可能大家还会有一些疑问。下面来详细讲一下。

pending callbacks

这个阶段其实是处理由于操作系统出错,导致一些本应在上次事件循环中执行的回调。例如一些TCP错误。因此这部分,开发者不能主动操作,是NodeJs的一些容错机制。

check

同样的,setImmediate是nodejs特有的api,他可以立即创建一个异步宏任务。不仅如此,nodejs在事件循环中还专门设了一个check时期,在这个时期会专门执行setImmediate的回调。甚至你可以在这个时期中如果不停的产生setImmediate回调,eventloop会优先处理。

close callbacks

这个时期处理关闭事件,如socket.on('close', ...) 等这样可以确保在一些通讯结束前,所有任务都完成了。

微任务在eventloop中

我们先来回顾浏览器与nodejs的差异:

宏任务:

任务 浏览器 Node
I/O
setTimeout
setInterval
setImmediate
requestAnimationFrame

微任务:

任务 浏览器 Node
process.nextTick
MutationObserver
Promise.then catch finally

可以看到process.nextTick是nodejs特有的微任务,不仅如此,process.nextTick()的优先级高于所有的微任务,每一次清空微任务列表的时候,都是先执行 process.nextTick()

执行差异

不仅是任务类型上有差异,在执行上2个环境其实也有差异。在浏览器上执行任务的时候,每执行一个宏任务之前,需要先确保微任务队列执行完了。而在nodejs上是每个时期之前,先确保微任务队列执行完。也就是说在假如在timer时期,会先把所有setTimeout,setInterval的宏任务执行完。在执行完微任务,再进入下个时期。

注意:以上执行规则是在nodejs的v11版本之前的规则。在11版本之后nodejs的执行输出是跟浏览器一样的。

setImmediate() vs setTimeout()

setImmediate() 和 setTimeout()的执行先后顺序是不一定的,就是说如果你不停地执行以下代码,每次得到的结果可能是不一样的。

setTimeout(() => {
  console.log('timeout');
}, 0);

setImmediate(() => {
  console.log('immediate');
});

其中的原因是程序对时间的处理是有误差的。在setTimeout方法中设置的时间,不一定是准确的。同时在回调触发时,也无法确认事件循环处在哪个时期,可能是timer,也可能是check。所有会有不同的结果。

总结

eventloop是js运行机制里的重点内容,对于NodeJs来说,eventloop的操作空间则更大。因为它被细分为不同的时期,从而让我们可能把逻辑进一步细化。同时利用nextTick的最高优先级,可以写出在浏览器无法实现的代码。因此对于深入NodeJs的开发者来说,eventloop往往是他们考察新人对NodeJs理解的第一步。

更多node相关知识,请访问:nodejs 教程!!

以上がこの記事では、Node.js のイベントループについて理解します。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。