Node.js はシングル プロセス、シングル スレッド アプリケーションですが、V8 エンジンが提供する非同期実行コールバック インターフェイスにより、大量の同時実行を処理できるため、パフォーマンスは非常に高くなります。
Node.js のほぼすべての API はコールバック関数をサポートしています。
基本的に、Node.js のすべてのイベント メカニズムは、デザイン パターンのオブザーバー パターンを使用して実装されます。
Node.js のシングル スレッドは、イベント オブザーバーが存在しなくなるまで while(true) イベント ループに入るのと似ており、非同期イベントごとにイベント オブザーバーが生成され、イベントが発生するとコールバック関数が呼び出されます。
Node.js はイベント駆動型モデルを使用しており、Web サーバーはリクエストを受信すると、リクエストを閉じて処理し、次の Web リクエストを処理します。
リクエストは完了すると処理キューに戻され、キューの先頭に到達すると結果がユーザーに返されます。
Web サーバーは読み取りまたは書き込み操作を待たずに常にリクエストを受け入れるため、このモデルは非常に効率的でスケーラブルです。 (これはノンブロッキング IO またはイベント駆動型 IO とも呼ばれます)
イベント駆動型モデルでは、イベントをリッスンするためにメイン ループが生成され、イベントが検出されるとコールバック関数がトリガーされます。
イベント駆動型プロセス全体がこの方法で実装され、非常に簡潔になります。 オブザーバー パターンとある程度似ており、イベントはサブジェクト (Subject) に相当し、このイベントに登録されたすべてのハンドラーはオブザーバー (Observer) に相当します。
Node.js には複数の組み込みイベントがあります。次の例に示すように、イベント モジュールを導入し、EventEmitter クラスをインスタンス化することで、イベントをバインドしてリッスンできます。
// イベントモジュールをインポート
var events = require('events');
//eventEmitterオブジェクトを作成する
var eventEmitter = new events.EventEmitter();
次のプログラムはイベント ハンドラーをバインドします。
// イベントとイベント ハンドラーをバインドする
eventEmitter.on('eventName', eventHandler);
プログラムでイベントをトリガーできます。
// イベントをトリガーする
eventEmitter.emit('eventName');
main.js ファイルを作成します。コードは次のとおりです。
// イベントモジュールをインポート
var events = require('events');
//eventEmitterオブジェクトを作成する
var eventEmitter = new events.EventEmitter();
// イベントハンドラを作成する
var connectHandler = function connected() {
console.log('接続に成功しました。');
// data_received イベントを起動します
eventEmitter.emit('data_received');
}
// バインド接続イベント ハンドラー
eventEmitter.on('connection', connectHandler);
// 匿名関数を使用して data_received イベントをバインドします
eventEmitter.on('data_received', function(){
console.log('データは正常に受信されました。');
});
// 接続イベントをトリガーします
eventEmitter.emit('connection');
console.log("プログラムが実行されました。");
次に上記のコードを実行してみましょう:
$ node main.js 接続に成功しました。 データは正常に受信されました。 プログラムの実行が完了しました。
Node アプリケーションでは、非同期操作を実行する関数は最後の引数としてコールバック関数を受け取ります。 コールバック関数は、最初のパラメータとしてエラー オブジェクトを受け取ります。
前の例に戻って、次の内容の input.txt を作成してみましょう。
htmlチュートリアル: w3cstudy.cc
main.js ファイルを作成します。コードは次のとおりです。
var fs = require("fs");
fs.readFile('input.txt', function (err, data) {
if (err){
console.log(err.stack);
return;
}
console.log(data.toString());
});
console.log("プログラムの実行が完了しました");
上記のプログラムでは、 fs.readFile() はファイルを読み取るための非同期関数です。 ファイルの読み取り中にエラーが発生した場合、err オブジェクトはエラー メッセージを出力します。
エラーが発生しない場合、readFile は err オブジェクトの出力をスキップし、ファイルの内容はコールバック関数を通じて出力されます。
上記のコードを実行すると、実行結果は次のようになります。
プログラムの実行が完了しました htmlチュートリアル: w3cstudy.cc
次に、input.txt ファイルを削除します。実行結果は次のようになります。
プログラムの実行が完了しました Error: ENOENT, open 'input.txt'
input.txtファイルが存在しないため、エラーメッセージが出力されました。