「server.js」の以下のコメントを外して、Node.jsを再実行してみましょう。
//res.writeHead(200, {'Content-Type':'text/html; charset=utf-8'}); //res.end();
Webブラウザで、「http://127.0.0.1:8192/」を開いても、index.htmlが表示されません。
index.htmlの読み込みが完了する前に、HTTPレスポンスを返してしまったためです。
「res.end()」を呼び出すと、レスポンス生成の完了が、Node.jsに通知されます。その時点で、index.htmlの読み込み完了を待たずにレスポンスをWebブラウザに返してしまいます。そのため、index.htmlの中身は表示されません。
では次に、readFileソッドの「res.end()」をすべてコメントアウトして実行してみましょう。
// httpとfsモジュールを読み込む var http = require('http'), fs = require('fs'); // httpサーバの作成 http.createServer(function(req, res) { console.log("start"); // index.htmlを読み込んで表示 fs.readFile('index.html', function(err, content) { if (err) { throw err; } console.log("response end"); res.writeHead(200, {'Content-Type':'text/html; charset=utf-8'}); // res.end(content); }); console.log("end"); // index.htmlの読み込みを待たずにレスポンスを返す //res.writeHead(200, {'Content-Type':'text/html; charset=utf-8'}); //res.end(); }).listen(8192, '127.0.0.1'); console.log('http://127.0.0.1:8192/');
「res.end()」がないため、Node.jsはレスポンス生成の完了を検知できずブロックし続けます。HTTPレスポンスを返さないため、Webブラウザが応答待ち状態になります。2分くらいすると、タイムアウトが発生します。
Webブラウザが応答待ち状態で次々にWebブラウザを開くと、どうなるでしょうか?
イベントがどんどんキューにたまっていきますが、イベントハンドラは最初のHTTPレスポンス待ち状態でブロックされてしまいます。
ログを見ても最初のリクエストの「start」「end」「response end」が表示されたまま止まってしまいます。最初のリクエストのタイムアウトが発生すると、次のリクエストの「start」「end」「response end」が表示されます。
このように、イベントハンドラでブロックしてしまうと、後続のイベントが実行待ち状態になってしまいます。
イベントループ・モデルでプログラムを組む場合、処理をブロックしないよう注意する必要があります。
Webアプリケーションで重たい処理を実行する場合は、いったんレスポンスを返して、バックグラウンドで処理を実行し、終わったら通知するような仕組みで実装することをお勧めします。
バックグラウンドの処理完了を通知する仕組みとしては、Ajaxで定期的に監視する方法やComet、WebSocketなどを使ったリアルタイムに通知する方法あります。
Node.jsを使うメリットは、まさにこのリアルタイム通信にあると私は思います。次回は、Ajax、Comet、WebSocketを例にしてNode.jsを説明したいと思います。
Copyright © ITmedia, Inc. All Rights Reserved.