Smashing Node.js に書いてあるEffective Node.jsなこと(第二弾) - from scratch

この記事は、東京Node学園祭2012 アドベントカレンダーの25日目の記事です。もうすぐで完走ですね!

あ〜、大分時間があいてしまった。
というわけで第二弾行ってみましょう。

今回は以下の箇所から紹介します。

  • CHAPTER 5: CLIとFS APIについて
  • CHAPTER 6: TCPについて
  • CHAPTER 7: HTTPについて
  • CHAPTER 8: CONNECT

に書かれていることから今回もEffective Node.jsなことを紹介していきます。

■8. コンソールに色を付けておくと捗る。
Smashing Node.jsを読んでると本当にコンソール出力にバンバン色を付けてカラフルにしてます。まぁNodeに限らないのでしょうが、色をつけておくと捗るみたいなので、是非真似しましょう。


console.log('\033[31m' + 'Hello World'+ '\033[39m');


console.log('\033[33m'+ 'Hello World'+  '\033[39m');


console.log('\033[36m' + 'Hello World' + '\033[39m');


console.log('\033[90m' + 'Hello World' + '\033[39m');


console.log('\033[32m ' + 'Hello World'+ ' \033[39m');

実行結果:
f:id:yosuke_furukawa:20121108003716p:plain

ちなみに"¥033"までがエスケープ文字列、[NN(NNは数字。)で色指定。最後のmで続く文字列をくるんで装飾するという意味らしい。詳しくは以下のページに書いてある。

ANSI escape code - Wikipedia, the free encyclopedia

いやいや、こんな文字列覚えられないよ、っていう人はnpmに'colors'っていうモジュールがあるのでそれを使いましょう。

require('colors');

console.log( 'Hello World'.red);

console.log( 'Hello World'.yellow);

console.log( 'Hello World'.cyan);

console.log( 'Hello World'.grey);

console.log( 'Hello World'.green);

でもcolorsはStringのprototype拡張するから、その辺り、一応注意ね。

■9. ショートカット作っておいたほうが捗る
■エコースクリプトを作る。


console.log("input something:");
process.stdin.resume();
process.stdin.setEncoding("utf8");
process.stdin.on('data', function(data) {
  process.stdout.write(data);
});

実行すると単なるエコーするスクリプト。
コレよく読むとprocessって毎回書いてて面倒だよね。
微妙に見難いし。


var log = console.log;
var stdin = process.stdin;
var stdout = process.stdout;


log('input something:');
stdin.resume();
stdin.setEncoding('utf8');
stdin.on('data', function(data) {
    stdout.write(data);
});


割りとやっている人はやっている関数のショートカット登録。smashing node.jsでもチラホラ出てきます。書く時に楽なので、割りといいかも。
(上の例くらいの量なら使わなくてもいいかも知れないけど。)

■10. 重たいファイルを扱う時はStream、あとpipeは抑えておこう。
httpで、画像ファイルとかの大きいファイルを扱う時はstreamを使いましょう。
どんなときもstreamは重要だから抑えておこう。

require('http').createServer(function(req, res) {
  res.writeHead(200, { 'Content-Type'; 'image/png');
  var stream = require('fs').createReadStream('image.png');
  stream.on('data', function(data) {
    res.write(data);
  });
  stream.on('end', function(data) {
    res.end();
  });
}).listen(3000);

StreamはJxckさんの資料が参考になる。

ちなみにStreamにはpipe()っていう便利メソッドがあって、上の処理をシンプルに書くことが出来る。

pipe使った後はこうなる。

require('http').createServer(function(req, res) {
    res.writeHead(200, { 'Content-Type': 'image/png' } );
    require('fs').createReadStream('image.png').pipe(res);
}).listen(3000);

■11. httpのリクエスト系モジュールはsuperagentが便利。
nodeのhttpモジュールにはrequestっていう他のサイトにリクエストを発行するメソッドがある。こんなかんじで使う。

require('http').request({
    host: '127.0.0.1'
  , port: 3000
  , url: '/'
  , method: 'GET'
}, function (res) {
    var body = '';
    res.setEncoding('utf8');
    res.on('data', function(chunk) {
        body += chunk;
    });
    res.on('end', function() {
        console.log('\n We got: \033[96m' + body + '\033[39m\n');
    });
}).end();

ちなみにGETするだけならgetっていうメソッドのが良い。

require('http').get({
    host: '127.0.0.1'
  , port: 3000
  , url: '/'
}, function (res) {
    var body = '';
    res.setEncoding('utf8');
    res.on('data', function(chunk) {
        body += chunk;
    });
    res.on('end', function() {
        console.log('\n We got: \033[96m' + body + '\033[39m\n');
    });
});

細かい差だけど、わざわざmethodに'GET'って指定しなくていいし、終端にend()を入れる必要もない。

これでもまだ結構書かなきゃいけないなぁと思ったなら、 'superagent'使うと良い感じ。

var request = require('superagent');
request.get('http://127.0.0.1:3000/')
    .end(function(res) { 
        console.log('\n We got: \033[96m' + res.text + '\033[39m\n');
    });

実はこれはかなり便利。dataイベントをもらってバッファもしてくれるし、最終的な結果はJSONオブジェクトとしてもらえるので、加工が簡単。

詳しくはコチラ。
visionmedia/superagent · GitHub

■12. nodeのwebアプリケーションで再起動しないで変更を反映する方法(upモジュールについて)
Node.jsでwebアプリケーション作っているとプロセスを再起動しないと変更が読み込まれないということに気づくと思う。

そんな時はupモジュール。upモジュールを使うとコードの反映がブラウザの読み込みボタンだけで出来る。
upモジュールを使うには、まずnpmでupをインストールして。

> npm install up -g

サーバーを作成。この時、サーバーのインスタンスをmodule.exportsでupモジュールから読み込めるようにしておく。

module.exports = require('http').createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.end('Hello World');
});

こうしておいて、upコマンドで起動する。

> up --watch --port 3000 server.js

こうすると、server.jsへの変更が即座に反映される。

module.exports = require('http').createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.end('Hello <b>World</b>');
});

試しに上のように変更してからブラウザで読み込んでみるといい。
即座に反映されるのがわかると思う。

※Smashing nodeに書いていない注意点:
でもupモジュールはmasterがworkerプロセスに接続をつなぐ処理が必要になるため、普通にserverを起動するよりも多少性能劣化する。それでもホットデプロイに近いことがやりたい場合に使う方が良い。

普通に開発環境ならコードの変更を読み取って通常の再起動をしてくれるやり方で問題ないはず。それだけならnodemon、node-dev、みんな大好きforeverでも出来る。

ちなみにgraceful restartという接続中のプロセスは殺さずに何もしていないプロセスを再起動するならatsuyaさんが作成したqilinモジュールが良い。これならupモジュールほど性能劣化を産まずに実環境でも使えるはず。

atsuya/qilin · GitHub
qilin - 思った事

この辺りの再起動ネタはいつかブログにまとめます。

まとめ
というわけでまた少しだけ紹介しました。
Smashing Node.jsも次からはConnect, Express, Socket.io等の有名モジュールに移っていきます。
Node.js入門も読み始めたので比較とかも面白いかもしれません。

ではでは。