JavaScript事件のメカニズムの実現を初めて見ました.
3959 ワード
ブラウザでは、イベントは極めて重要なメカニズムとして、JavaScriptがユーザ操作とDOMの変化に応答する能力を与える.Node.jsでは、イベント駆動モデルは高合併能力の基礎である.
JavaScriptを学ぶにも、その運用プラットフォームを理解する必要があります.JavaScriptのイベントモデルをよりよく理解するために、Nodeとブラウザのエンジンのソースコードから始めて、その底の実現を分析し、一連のブログに整理します.メモとして、皆さんとコミュニケーションしながら、分析と理解に偏りがあると思います.
イベント駆動モデルを簡単に説明する
JavaScript事件のモデル自体を説明するいい文章がもう多くなりました.これはもう腐った話題です.ここでは簡単に書いて、いい文章のリンクを提供します.
プログラムはどのようにイベントに応答しますか?
私たちのプログラムは外部のイベントに応答して、次の2つの方法があります.中断操作システムのキーボード処理などのハードウェア入力は中断によって行われることが利点であり、マルチスレッドがなくても安心して私達のコードを実行でき、CPUは中断信号を受信したら自動的に中断処理手順を実行し、処理が完了したら元のコードの実行環境を回復して実行し続けることができる.このような方法はハードウェアのサポートが必要で、一般的にはオペレーティングシステムによって実装されます. ポーリングサイクルは、イベントが発生したかどうかを検出し、ある場合は、対応する処理プログラムを実行する.これは下の層と上の層の開発に応用されています.Windowsウィンドウプログラムは、メインスレッドに次のコードを書く必要があり、通常はメッセージループと呼ばれる. 関連する討論は、事件をブラウザで処理することについて知っていますか?匿名ユーザーの回答:この回答は非常によく、イベントloopの動作原理を理解するのに役立ちます.答えの最後にいくつかの文章があります. MDN-Concerency model and Event Loop:MDN上のevent loopの紹介. Nodeの中のイベントloop
Nodeのソースコードを通してイベントloopの実現を見ます.
Nodeは、V 8をJavaScriptの実行エンジンとして、libuvを使ってイベント駆動式非同期I/Oを実現します.そのイベントサイクルは、libuvのデフォルトのイベントサイクルを採用しています.
src/node.ccでは、
次にNodeは、は、 もし 最後に
libuvでは、イベントループのたびに自分のタイムマシンを更新して、タイマー機能を実現します.I/Oイベントは2つに分類されます. Network I/Oは、システムを使用して提供される非ブロッキングI/Oソリューションであり、例えばLinux上でepollを使用し、windows上でIOCPを使用する. ファイル操作とDNS操作にはシステム解決策がないので、libuvはスレッドプールを自己構築し、閉塞式I/Oを行う. また、ユーザー定義の関数をスレッドに投げて実行してもいいです.運行終了後には、メインラインで該当するコールバック関数を実行しますが、Nodeはこの機能をJavaScriptに追加していません.つまり、元のNodeだけでは、JavaScriptで新しいスレッドを開いて並行して実行することはできません.
関連資料 libuv Design Overview:libuvに関するアーキテクチャ及び設計構想. node child_process'exit':Nodeのchild_process'exit事件. Node with threads:libuvスレッド池を使ってJavaScriptコードを非同期的に実行することを議論した. 下一篇:JavaScript事件のメカニズムの実現を初めて見ます.
JavaScriptを学ぶにも、その運用プラットフォームを理解する必要があります.JavaScriptのイベントモデルをよりよく理解するために、Nodeとブラウザのエンジンのソースコードから始めて、その底の実現を分析し、一連のブログに整理します.メモとして、皆さんとコミュニケーションしながら、分析と理解に偏りがあると思います.
イベント駆動モデルを簡単に説明する
JavaScript事件のモデル自体を説明するいい文章がもう多くなりました.これはもう腐った話題です.ここでは簡単に書いて、いい文章のリンクを提供します.
プログラムはどのようにイベントに応答しますか?
私たちのプログラムは外部のイベントに応答して、次の2つの方法があります.
MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
メッセージループは、メッセージ(ユーザのUI操作、システムメッセージなど)があるかどうかを継続的に検出し、ある場合はメッセージを配信し、対応するコールバック関数を呼び出して処理する.ポーリング方式の欠点の一つは、メインスレッドのメッセージサイクルで時間をつぶして操作すると、プログラムが新しいメッセージにすぐに応答できなくなるということです.これはJavaScriptの中では明らかに表現されています.今後もこの点に言及し、その解決策を検討します.しかし、JavaScriptには同様のメッセージ循環コードがありません.イベントを簡単に登録し、呼び出しを待つだけです.これはブラウザ、Nodeが実行プラットフォームとして、すでにイベントloopを実現しました.JavaScriptコードはこの過程に介入する必要がなく、调节者として静かに待てばいいです.Nodeのソースコードを通してイベントloopの実現を見ます.
Nodeは、V 8をJavaScriptの実行エンジンとして、libuvを使ってイベント駆動式非同期I/Oを実現します.そのイベントサイクルは、libuvのデフォルトのイベントサイクルを採用しています.
src/node.ccでは、
Environment* env = CreateEnvironment(
node_isolate,
uv_default_loop(),
context,
argc,
argv,
exec_argc,
exec_argv);
このコードは、nodeの実行環境を確立し、第3行のuv_default_loop()
が見られ、これはlibuvライブラリの関数であり、uvライブラリ自体およびdefault_loop_struct
を初期化し、ポインタdefault_loop_ptr
を返す.その後、Nodeは実行環境をロードし、設定操作を完了し、イベントloopを起動します.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
は、次のループが行われるかどうかを識別するために使用される.env->event_loop()
は、env
に保存されているdefault_loop_ptr
に戻ります.uv_run
は、指定されたUV_RUN_ONCE
モードでlibuvのイベントloopを起動します.このようなモードでは、uv_run
は、少なくとも1つのイベントを処理することができる.これは、現在のイベントキューに処理が必要なI/Oイベントがない場合、I/Oイベントがあるまで、uv_run
はブロックされることを意味する.現在I/Oイベントがなく、タイマーイベントもない場合、uv_run
はfalseに戻る.次にNodeは、
more
の場合に基づいて、次のステップの動作を決定する.more
がtrue
であれば、次のloop
を継続して実行する.more
がfalse
であるならば、処理待ちのイベントがすでにないと説明し、EmitBeforeExit(env);
がプロセスの'beforeExit'
イベントをトリガし、対応する処理関数を検査して処理し、完了したら直接ループから飛び出す.'exit'
イベントをトリガし、対応するコールバック関数を実行し、Node実行が終了し、後にいくつかのリソースリリース動作が行われる.libuvでは、イベントループのたびに自分のタイムマシンを更新して、タイマー機能を実現します.I/Oイベントは2つに分類されます.
関連資料