ホームページ >ウェブフロントエンド >jsチュートリアル >Node.js イベント駆動_node.js
Node.js イベント駆動型実装の概要
「イベント」は ECMAScript 標準では明確に定義されていません (また、必須ではありません)。イベントはブラウザーで非常に重要なメカニズムとして機能し、JavaScript に Node.js でのユーザー操作や DOM の変更に応答する機能を提供します。 、非同期イベント駆動モデルは、その高い同時実行機能の基礎です。
JavaScript を学習するには、その実行プラットフォームを理解することも必要です。JavaScript のイベント モデルをより深く理解するために、ノードとブラウザ エンジンのソース コードから始めて、その基礎となる実装を分析し、一連のブログ投稿にまとめていく予定です。 ; これはメモである一方で、分析と理解に漏れや偏りがあれば、修正していただければ幸いです。
イベント駆動型モデルの簡単な説明
JavaScript イベント モデル自体については、すでに多くの優れた記事が説明されていますが、ここでは簡単に説明し、いくつかの優れた記事へのリンクを提供します。
プログラムがイベントにどのように応答するか
私たちのプログラムは、次の 2 つの方法で外部イベントに応答します:
中断
オペレーティング システムは割り込みを通じてキーボードやその他のハードウェア入力を処理します。この方法の利点は、マルチスレッドを使用しなくても、CPU が割り込み信号を受信した後、自動的にコードを実行できることです。対応する割り込みハンドラが完了すると、元のコードの実行環境が復元され、実行が継続されます。この方法にはハードウェアのサポートが必要で、通常はオペレーティング システムによってカプセル化されます。
ポーリング
ループしてイベントが発生したかどうかを検出し、発生した場合は対応するハンドラーを実行します。これは、下位レベルの開発と上位レベルの開発の両方に当てはまります。
Windows ウィンドウ プログラムは、通常メッセージ ループと呼ばれるメイン スレッドに次のコードを記述する必要があります。
MSG msg = { }; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }
ポーリング方式の欠点の 1 つは、時間のかかる操作がメイン スレッドのメッセージ ループで実行されると、プログラムが新しいメッセージにタイムリーに応答できないことです。これは JavaScript で明らかであり、その解決策とともに後で説明します。
ノード内のイベントループ
Node ソース コードによるイベント ループの実装を見てみましょうノードは JavaScript 実行エンジンとして V8 を使用し、libuv を使用してイベント駆動型の非同期 I/O を実装します。そのイベント ループは、libuv のデフォルトのイベント ループを使用します。
src/node.cc 内、
Environment* env = CreateEnvironment( node_isolate, uv_default_loop(), context, argc, argv, exec_argc, exec_argv);
その後、ノードは実行環境をロードしていくつかのセットアップ操作を完了し、イベント ループを開始します:
bool more; do { more = uv_run(env->event_loop(), UV_RUN_ONCE); if (more == false) { EmitBeforeExit(env); // Emit `beforeExit` if the loop became alive either after emitting // event, or after running some callbacks. more = uv_loop_alive(env->event_loop()); if (uv_run(env->event_loop(), UV_RUN_NOWAIT) != 0) more = true; } } while (more == true); code = EmitExit(env); RunAtExit(env); ...
次のノードは、その他の状況に基づいて次のステップを決定します:
さらに当てはまる場合は、次のループの実行を続けます。
more が false の場合、処理を待機しているイベントがないことを意味します。EmitBeforeExit(env); は、プロセスの「beforeExit」イベントをトリガーし、対応する処理関数をチェックして処理し、ループから直接抜け出します。完成後。
最後に、「exit」イベントがトリガーされ、対応するコールバック関数が実行され、ノード操作が終了し、後でいくつかのリソース解放操作が実行されます。
libuv では、タイマー イベントはイベント ループ内で直接処理されますが、I/O イベントは 2 つのカテゴリに分類されます。
ネットワーク I/O は、Linux の epoll や Windows の IOCP など、システムによって提供されるノンブロッキング I/O ソリューションを使用します。
ファイル操作と DNS 操作には (適切な) システム ソリューションがないため、libuv はブロッキング I/O を実行する独自のスレッド プールを構築しました。
さらに、カスタム関数をスレッド プールにスローして実行することもできます。操作の完了後、メイン スレッドは対応するコールバック関数を実行します。ただし、Node はこの関数を JavaScript に追加していません。ネイティブ ノードを使用して並列実行するために JavaScript で新しいスレッドを開くことは不可能です。
以上がこの記事の全内容です。皆さんに気に入っていただければ幸いです。