Node.jsは、サポートされているOS(少なくとも、Unix、OS X、およびWindows)によって提供される非同期(非ブロッキング)入出力用のapis/syscallsを抽象化するクロスプラットフォームライブラリであるlibuvに基づいて構築されています。
非同期IO
このプログラミングモデルでは、ファイルシステムによって管理されるデバイスとリソース(ソケット、ファイルシステムなど)でのオープン/読み取り/書き込み操作は、呼び出し元のスレッドをブロックせず(通常の同期cのようなモデルのように)、マークを付けるだけです。新しいデータまたはイベントが利用可能になったときに通知されるプロセス(カーネル/ OSレベルのデータ構造)。Webサーバーのようなアプリの場合、プロセスは、通知されたイベントがどのリクエスト/コンテキストに属しているかを把握し、そこからリクエストの処理を続行する責任があります。これは必然的に、OSへのリクエストを発信したスタックフレームとは異なるスタックフレームにいることを意味することに注意してください。OSは、シングルスレッドプロセスが新しいイベントを処理するためにプロセスのディスパッチャに譲らなければならなかったためです。
私が説明したモデルの問題は、それが本質的に非シーケンシャルであるため、プログラマーにとってなじみがなく、推論するのが難しいことです。「関数Aでリクエストを行い、その結果を別の関数で処理する必要があります。この場合、Aのローカルユーザーは通常利用できません。」
ノードのモデル(継続渡しスタイルとイベントループ)
Nodeは、JavaScriptの言語機能を活用して、プログラマーに特定のプログラミングスタイルを採用するように誘導することで、このモデルをもう少し同期的に見えるようにするという問題に取り組んでいます。IOを要求するすべての関数には、のような署名がfunction (... parameters ..., callback)あり、要求された操作が完了したときに呼び出されるコールバックを与える必要があります(ほとんどの時間は、OSが完了を通知するのを待つために費やされることに注意してください。他の仕事に費やした)。Javascriptのクロージャのサポートにより、コールバックの本体内の外部(呼び出し)関数で定義した変数を使用できます。これにより、ノードランタイムによって個別に呼び出されるさまざまな関数間の状態を維持できます。継続渡しスタイルも参照してください。
さらに、IO操作を生成する関数を呼び出した後、呼び出し元の関数は通常return、ノードのイベントループを制御します。このループは、実行がスケジュールされた次のコールバックまたは関数を呼び出します(おそらく、対応するイベントがOSによって通知されたため)。これにより、複数の要求の同時処理が可能になります。
ノードのイベントループは、カーネルのディスパッチャーにいくらか似ていると考えることができます。カーネルは、保留中のIOが完了すると、ブロックされたスレッドの実行をスケジュールし、ノードは、対応するイベントが発生したときにコールバックをスケジュールします。
高度な同時実行、並列処理なし
最後に、「コードを除いてすべてが並行して実行される」というフレーズは、すべてのjsを多重化してシーケンス処理することにより、ノードが1つのスレッドで数十万のオープンソケットからのリクエストを同時に処理できるようにするポイントをキャプチャするという適切な役割を果たします。単一の実行ストリームのロジック(「すべてが並列で実行される」と言っても、ここではおそらく正しくありません。並行性と並列性を参照してください。違いは何ですか?)。ほとんどの時間は実際にはネットワークまたはディスク(データベース/ソケット)の待機に費やされ、ロジックは実際にはCPUに負荷をかけないため、これはWebアプリケーションサーバーで非常にうまく機能します。つまり、これはIOバウンドワークロードでうまく機能します。