Node.js のイベントループ機構について説明する記事
この記事は、Node.js のイベント ループ (タイム ループ) メカニズムを理解するのに役立ちます。
今日は、nodeJ のイベント ループについて学びます。イベントループを理解するのは私にとって常に大きな困難でしたが、今回の学習を通じてその困難を突破したいと思いますし、このブログを通してイベントループについての理解と感想を深めていきたいと思っています。
libuv
イベントループを学ぶ前に、まずノードの libuv について理解してください。 libuv は、さまざまなオペレーティング システムでのさまざまな I/O モデルの実装を担当し、さまざまな実装をサードパーティ アプリケーションで使用できる API に抽象化します。
質問
イベント ループを正式に学習する前に、質問について考えてみましょう
setTimeout(() => { console.log("timer1"); Promise.resolve().then(() => { console.log("promise1"); }); }, 0); setTimeout(() => { console.log("timer2"); Promise.resolve().then(() => { console.log("promise2"); }); }, 0);
このコードは何ですかブラウザで実行した結果でしょうか?
ノードで実行した結果はどうなりますか?
#ノード 8.6 前:
なぜこのような結果になるのか、後で分析します!
まず、画像を見てみましょう:
#画像には 6 つのステージ、つまりタイマー、保留中のコールバック、アイドル/準備、ポーリング、チェック、クローズ コールバックが表示されます。
- タイマー フェーズ: 主に setTimeOut、setInterval コールバックを実行します。
- 保留中のコールバック フェーズ: ネットワーク通信エラー コールバックなどの一部のシステム コール エラーを実行します
- アイドル/準備フェーズ: システム内でのみ使用されます (このフェーズを制御したり干渉したりすることはできません)
- ポーリング フェーズ: 新しい I/ を取得します。ファイルを読み取るための I/O コールバックの取得などの O イベント。
- 適切な状況下では、nodejs はこのフェーズでブロックします
- たとえば、sokect を実行します。イベント コールバックの破棄とクローズ
- 各ステージは、
(先入れ先出し) ルールに従って、内部のタスク キュー タスクを実行します。 これら 6 つのステージのうち、タイマー、ポーリング、チェック ステージに焦点を当てます。私たちの日常の開発における非同期タスクのほとんどは、これら 3 つの段階で処理されます。
タイマーまずタイマーの段階について話しましょう。
タイマーはイベント ループの最初のステージです。Nodejs は期限切れのタイマーがあるかどうかを確認し、期限切れになっている場合はコールバックをキューに入れます。ただし、nodejs は、事前に設定されたイベントが到着したときにすぐにタイマーがコールバックを実行することを保証できません。これは、nodejs によるタイマーの有効期限チェックが必ずしも信頼できるわけではないためです。マシン上で実行されている他のプログラムの影響を受けるか、現在のメインスレッドが発生しました。アイドル状態ではありません。
ここでの不確実性については、公式サイトに例が示されています: まずsetTimeOutを宣言してから、外部からファイルを読み込む このように、ファイルの読み込み操作がタイマー時間を超えた場合、読み込んだファイルは操作によりタイマーのコールバックが遅延します。これは、前述したようにメインスレッドがアイドル状態ではない状況です。
ポーリング フェーズでは主に 2 つのことを実行します:
1. ポーリング フェーズのタスク キューの処理
2タイムアウトになったタイマーがある場合、そのコールバック関数が実行されます
上の図では、次のことも確認できます。
ここで質問なのですが、投票段階でブロックされてしまうと、設定したタイマーは実行できなくなるのではないでしょうか?
実際にはイベント ループがポーリング フェーズでブロックされている場合、nodejs にはチェック メカニズムがあり、タイマー キューが空かどうかをチェックします。空でない場合は、タイマーに再入力されます。段階。
チェックフェーズでは主に setImmediate コールバック関数が実行されます。
小总结
event-loop的每个阶段都有一个队列,当event-loop达到某个阶段之后,将执行这个阶段的任务队列,直到队列清空或者达到系统规定的最大回调限制之后,才会进入下一个阶段。当所有阶段都执行完成一次之后,称event-loop完成一个tick。
案例
上面我们说完了event-loop的理论部分,但是光有理论我们也还是不能很清晰的理解event-loop。下面我们就根据几个demo来更加深入的理解下event-loop!
demo1
const fs=require('fs') fs.readFile('test.txt',()=>{ console.log('readFile') setTimeout(()=>{ console.log('settimeout'); },0) setImmediate(()=>{ console.log('setImmediate') }) })
执行结果:
可见执行结果跟我们前面的分析时一致的!
demo2
const fs = require("fs"); const EventEmitter = require("events").EventEmitter; let pos = 0; const messenger = new EventEmitter(); messenger.on("message", function (msg) { console.log(++pos + " message:" + msg); // }); console.log(++pos + " first"); // process.nextTick(function () { console.log(++pos + " nextTick"); // }); messenger.emit("message", "hello!"); fs.stat(__filename, function () { console.log(++pos + " stat"); // }); setTimeout(function () { console.log(++pos + " quick timer"); // }, 0); setTimeout(function () { console.log(++pos + " long timer"); // }, 30); setImmediate(function () { console.log(++pos + " immediate"); // }); console.log(++pos + " last"); //
结果:
了解下浏览器和node的event-loop差异在什么地方
在node 8.6 之前:
浏览器中的微任务队列会在每个宏任务执行完成之后执行,而node中的微任务会在事件循环的各个阶段之间执行,即每个阶段执行完成之后会去执行微任务队列。
在8.6之后:
浏览器和node中微任务的执行是一致的!
所以,在文章开头,我们提出的思考的问题就有了结果。
关于 process.nextTick()和setImmediate
process.nextTick()
语法:process.nextTick(callback,agrs)
执行时机:
这个函数其实是独立于 Event Loop 之外的,它有一个自己的队列,当每个阶段完成后,如果存在 nextTick 队列,就会清空队列中的所有回调函数,并且优先于其他 microtask 执行。递归的调用process.nextTick()
会导致I/O starving,官方推荐使用setImmediate()
关于starving现象的说明:
const fs = require("fs"); fs.readFile("test.txt", (err, msg) => { console.log("readFile"); }); let index = 0; function handler() { if (index >= 30) return; index++; console.log("nextTick" + index); process.nextTick(handler); } handler();
运行结果:
可以看到,等到nextTick函数呗执行30次之后,读取文件的回调才被执行!这样的现象被称为 I/O 饥饿。
当我们把 process.nextTick 换为 setImmediate
const fs = require("fs"); fs.readFile("test.txt", (err, msg) => { console.log("readFile"); }); let index = 0; function handler() { if (index >= 30) return; index++; console.log("nextTick" + index); setImmediate(handler); } handler();
结果:
造成这两种差异的原因是,嵌套调用的setImmediate的回调被排到了下一次event-loop中去!
event-loop核心思维导图
结束语
通过今天的学习,让我对event-loop的理解更深刻了。那么,下次见。好好学习,天天向上!
更多编程相关知识,请访问:编程视频!!
以上がNode.js のイベントループ機構について説明する記事の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









ノンブロッキングおよびイベント駆動に基づいて構築されたノード サービスには、メモリ消費量が少ないという利点があり、大量のネットワーク リクエストの処理に非常に適しています。大量のリクエストを前提として、「メモリ制御」に関する問題を考慮する必要があります。 1. V8 のガベージ コレクション メカニズムとメモリ制限 Js はガベージ コレクション マシンによって制御されます

この記事では、NodeJS V8 エンジンのメモリとガベージ コレクター (GC) について詳しく説明します。

ファイル モジュールは、ファイルの読み取り/書き込み/開く/閉じる/削除の追加など、基礎となるファイル操作をカプセル化したものです。ファイル モジュールの最大の特徴は、すべてのメソッドが **同期** と ** の 2 つのバージョンを提供することです。 asynchronous**、sync サフィックスが付いているメソッドはすべて同期メソッドであり、持たないメソッドはすべて異種メソッドです。

ノード用の Docker イメージの選択は些細なことのように思えるかもしれませんが、イメージのサイズと潜在的な脆弱性は、CI/CD プロセスとセキュリティに大きな影響を与える可能性があります。では、最適な Node.js Docker イメージを選択するにはどうすればよいでしょうか?

Node 19 が正式リリースされましたので、この記事では Node.js 19 の 6 つの主要な機能について詳しく説明します。

Node.js はどのように GC (ガベージ コレクション) を行うのでしょうか?次の記事で詳しく説明します。

イベント ループは Node.js の基本的な部分であり、メイン スレッドがブロックされていないことを確認することで非同期プログラミングが可能になります。イベント ループを理解することは、効率的なアプリケーションを構築するために重要です。次の記事では、Node のイベント ループについて詳しく説明します。お役に立てれば幸いです。

ノードが npm コマンドを使用できない理由は、環境変数が正しく設定されていないためです。解決策は次のとおりです: 1. 「システムのプロパティ」を開きます; 2. 「環境変数」->「システム変数」を見つけて、環境を編集します。変数; 3.nodejs フォルダーの場所を見つけます; 4.「OK」をクリックします。
