Nodeのイベントループ

サーバサイドJavaScript Node.js入門 を年末に一読したのでまとめ。

Nodeのイベントループの概要

f:id:takaheraw:20130102201228p:plain

HTTPサーバのイベントループ

f:id:takaheraw:20130102205109p:plain

メインモジュールが読み込まれると、2.のステップでserver.listen(1337)までの初期スクリプトが実行される。3.のステップでクライアントから送られてくるネットワークデータを受信するI/Oイベントを待ち受ける。
クライアントからのHTTPリクエストによってネットワークデータを受信すると、I/Oイベントが発生し登録されたコールバックが実行される。 クライアントからのデータ受信が完了し、データ操作HTTPリクエストヘッダの解析が終了するとrequestイベントが発生し、HTTPレスポンスデータがクライアントに送信される。

非同期イベントの生成

f:id:takaheraw:20130102211353p:plain

process.nextTic()を使用してイベントを発生させると、必ずJavaScriptの実行がすべて完了した後にイベントがemittされる。

非同期コールバック

f:id:takaheraw:20130102212723p:plain

process.nextTick()のコールバック実行でcbが呼び出されるときは、すでにコンストラクタによるオブジェクトの生成が終わった後なのでfoo.setbazメソッドが実行することだできる。

Nodeのイベント駆動プログラミング

サーバサイドJavaScript Node.js入門 を年末に一読したのでまとめ。

イベントの処理の流れ

  • イベントを発生するオブジェクトを作成する
  • イベント発生時の処理関数(リスナ)を作成する
  • イベントを定義する
  • 任意のタイミングでイベントを発生させる

イベントを発生させるにはEventEmitterオブジェクトを利用

var events = require('events');
var emitter = new events.EventEmitter();

リスナ関数を作成

var sampleListener = function(arg1){
  console.log(arg1);
}

イベントを定義

emitter.on('occurrence', sampleListener);

イベントを発生させる

emitter.emit('occurrence', 'occured!');

Nodeのモジュール

サーバサイドJavaScript Node.js入門 を年末に一読したのでまとめ。

module.exportsによるモジュールの定義

module.exports = {
    funA: function(){        // 無名関数をfunAという名前で外部公開する
    }
}

function funB(){
}
module.exports.funB = funB;  // funBをfunBという名前で外部公開する

module.exports.objC = {
    foo: 'bar',              // objCという名前のオブジェクトを外部公開する
    fun: function(){
};

helloモジュールの定義

helloモジュールの利用

# pwd
/root/projects/node/5
# ls
hello.js
# node
> var hello = require('./hello');
undefined
> hello
{ say: [Function],
  getCount: [Function],
  resetCount: [Function] }
> hello.say('foo');
Hello foo
undefined
> hello.say('bar');
Hello bar
undefined
> hello.say('hoge');
Hello hoge
undefined
> hello.getCount();
3

1つのNodeプロセス内でrequire()を複数実行してもモジュールファイルが実行されるのはたった1度だけ

> require('./hello');
{ say: [Function],
  getCount: [Function],
  resetCount: [Function] }
> require('./hello');
{ say: [Function],
  getCount: [Function],
  resetCount: [Function] }
> hello.getCount();
3
> var hello = require('./hello');
undefined
> hello.getCount();
3

require()によるモジュールのロード

  • ../または./で始まるパスは相対パスとして解決
  • /で始まるパスは絶対パスとして解決
  • これら2つ以外のパスの場合は
    node_modulesディレクトリを検索して解決されたファイルのパス
    NODE_PATH環境変数の値を検索して解決されたファイルのパス
    から順にパスの解決が行われる。

メインモジュールかを判断する

モジュールがどこから読まれたかを確認

# node
> require.resolve('./hello')
'/root/projects/node/5/hello.js'
> require.resolve('http')
'http'

Node入門

サーバサイドJavaScript Node.js入門 を年末に一読したのでまとめ。

REPL

# node
> function fib(n) {
... if (n === 0 || n=== 1) return n;
... return fib(n-1) + fib(n-2);
... }
undefined
> for (var i = 0; i <= 10; i++) console.log(fib(i));
0
1
1
2
3
5
8
13
21
34
55
undefined

スクリプトファイルを実行

# node fib.js 
0
1
1
2
3
5
8
13
21
34
55

イベントループ

setTimeout(function() {
  console.log('Timed out');
}, 1000);
console.log('Waiting...');

HTTPサーバ

# node http1.js
Server running at http://192.168.11.14:1337/

nvmを使ったNodeとnpmのインストール手順

サーバサイドJavaScript Node.js入門 を年末に一読したのでまとめ。

OS

# cat /etc/redhat-release 
CentOS release 6.2 (Final)

nvmインストール

# git clone git://github.com/creationix/nvm.git ~/.nvm
# . ~/.nvm/nvm.sh
# nvm install v0.8.16

「command not found: shasum」 が発生した。aliasを設定すれば良いらしい。

# vim ~/.bashrc
alias shasum='sha1sum'
if [ -f ~/.nvm/nvm.sh ]; then
  source ~/.nvm/nvm.sh
  nvm use v0.8.16
fi

これでもインストールできず。以下をインストールしたら解決した。

# yum  -y install perl-Digest-SHA

再度インストール

# nvm install v0.8.16
# nvm use v0.8.16

ディレクトリ構造

.nvm
├── src
│   └── node-v0.8.16.tar.gz
└── v0.8.16
    ├── bin
    ├── include
    └── share

環境変数がセットされる。

#  printenv | grep NVM_
NVM_PATH=/root/.nvm/v0.8.16/lib/node
NVM_DIR=/root/.nvm
NVM_BIN=/root/.nvm/v0.8.16/bin

npmを使ったパッケージのインストール

モジュールをさがす

# npm search framework

パッケージをインストール

# npm install express

パッケージを確認

# npm ls

パッケージをグローバルにインストール

# npm install express -g

グローバルにインストール済みのパッケージ確認

# npm ls -g
/root/.nvm/v0.8.16/lib
└─┬ npm@1.1.69
    ├── abbrev@1.0.3
    ├── ansi@0.1.2
    ├── archy@0.0.2
    ├── block-stream@0.0.6
    ├── chownr@0.0.1
    ├── fstream@0.1.19
    ├─┬ fstream-npm@0.1.3
    │  └── fstream-ignore@0.0.5
    ├── glob@3.1.14
    ├── graceful-fs@1.1.14
    ├── inherits@1.0.0
    ├── ini@1.0.5
    ├─┬ init-package-json@0.0.6
    │  └── promzard@0.2.0
    ├── lockfile@0.2.1
    ├── lru-cache@2.0.4
    ├─┬ minimatch@0.2.9
    │  └── sigmund@1.0.0
    ├── mkdirp@0.3.4
    ├── node-gyp@0.7.3
    ├── nopt@2.0.0
    ├─┬ npm-registry-client@0.2.10
    │  └── couch-login@0.1.15
    ├─┬ npmconf@0.0.16
    │  └─┬ config-chain@1.1.3
    │      └── proto-list@1.2.2
    ├── npmlog@0.0.2
    ├── once@1.1.1
    ├── opener@1.3.0
    ├── osenv@0.0.3
    ├─┬ read@1.0.4
    │  └── mute-stream@0.0.3
    ├── read-installed@0.0.3
    ├── read-package-json@0.1.11
    ├── request@2.9.203
    ├── retry@0.6.0
    ├── rimraf@2.0.2
    ├── semver@1.1.1
    ├── slide@1.1.3
    ├── tar@0.1.14
    ├── uid-number@0.0.3
    └── which@1.0.5

Nodeとは何か

サーバサイドJavaScript Node.js入門 を年末に一読したのでまとめ。

Nodeとは

サーバサイドのプラットフォーム

特徴

  • スケーラビリティに優れたWebアプリケーションを簡単に作成できる
  • ネットワークI/OやファイルI/Oといった時間のかかる処理はすべて非同期
  • プログラムはJavaScriptで記述
  • JavaScriptで実現されたイベントループと非同期の仕組み、WebSocketプロトコルとの相性のよさ、Google社製の高効率なJavaScriptエンジンの掲載

よくある誤解