Node.js入門（開発環境セットアップ〜Hello Worldまで）

ドットインストール様を参考にしつつ、記事を書きました。

# 開発環境
- MacOS X 10.9(Mavericks)
- Vagrant 1.6.5
- VirtualBox 4.3.18
- CentOS6.5
- Node.js 0.10.30
	- 最新版は0.11.11（開発版）ですが、yumで入ったのがこのバージョンだったためこちらを使用しています
	- MacではHomebrewを利用することで0.11.11をインストールできます

# Node.jsとはなにか？
## 概要
> 大量のリクエストを高速にさばくアプリケーションを作るためのプラットフォーム

- 大規模なシステムの大量のリクエストをさばく部分を作るのに向いている
	- 例えばAPI、メッセージングなどの部分
	- Node.js単体でWebサービスを作ることも出来る
- 公式サイトは[nodejs.org](http://nodejs.org/)
	- [日本語版の公式サイト](http://nodejs.jp/)もある
	- [APIDocs](http://nodejs.org/api/)にAPIの詳細がある
- Node.jsは比較的頻繁に更新が行われている
	- APIに記載されているStabilityの値がAPIの安定度を表している
	- なるべく安定しているAPIを使うことを推奨

## 必要な知識
- Javascript
	- サーバサイドはJavaScriptで記述する
	- クライアントサイドJavaScriptとは少し違うが、基本的な文法は同じ
	- クライアント側がブラウザの場合はHTMLの知識も必要
		- クライアントがブラウザ（HTML）の場合、クライアント側のスクリプトもJavaScriptで記述出来るというメリットが有る
- Unixコマンド
	- コマンドラインでいろいろ行うため基本的な知識は必要

# 開発環境セットアップ
MacOSでのセットアップになります。
Windowsの方は他の記事を参考に仮想マシンのセットアップを行ってください。

## 仮想マシンのセットアップ
もう既に仮想環境あるよ、という人はスキップしてください。
仮想マシン用意しなくてもMac上でやるからいいよ、という人もスキップしてください。

```
$ mkdir dotinstall             # 開発用ディレクトリの作成
$ cd dotinstall
$ vagrant init chef/centos-6.5 # VagrantCloudでchefが公開しているboxを利用
$ vi Vagranfile                # Vagrantfileを編集
```

今回利用したboxは[こちら](https://vagrantcloud.com/chef/boxes/centos-6.5)のものです。
Vagrantfileは以下のように編集します。

```ruby:Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :

# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "chef/centos-6.5"
  config.vm.network "private_network", ip: "192.168.33.10"
end
```

`private_network`のipアドレスは、ご自分の環境に合わせてお好みで設定してください。

```
$ vagrant up # 仮想マシンの起動
```

ダウンロードはしばらくかかります。気長に待ちましょう。

## Node.jsのインストール
ダウンロードが終わったら仮想マシンに接続し、Node.jsをインストールします。

```
$ vagrant ssh
[vagrant@localhost ~]$ sudo yum update # yumのupdate
[vagrant@localhost ~]$ sudo rpm -ivh http://ftp.riken.jp/Linux/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm #epelリポジトリの追加
[vagrant@localhost ~]$ sudo yum install -y nodejs npm --enablerepo=epel # nodejsをyumでダウンロード
[vagrant@localhost ~]$ node -v
v0.10.30
[vagrant@localhost ~]$ npm -v
1.3.6
[vagrant@localhost ~]$ cd /vagrant # これ以降は共有ディレクトリで作業を行う
```
yumでnodeをインストールする方法は[こちら](http://qiita.com/you21979@github/items/4efd9fc4363573191b5c)を参考にさせていただきました。

### Macでのインストール
MacではHomebrewを利用することで最新版がインストールできます。

```
$ brew install node
```

Homebrewのインストール方法はこちらでは触れませんので、他の記事を参考にしてください。


### npmとは？
npmとは、nodeのパッケージを管理するためのツールです。
例えば、`npm install`コマンドを使うことで指定したパッケージをインストールできます。
今回は必要ありませんが、expressやsocket.ioのようなパッケージを利用する場合必要となります。

# スレッドモデルとイベントループ
## スレッドモデル
- Apacheなどで利用されている形式
- マルチスレッドで複数の処理をさばく
- スレッドは同時にひとつのものしか処理できない
	- スレッドを立ち上げるとメモリを消費する
	- メモリには制限があるので、立ち上げられるスレッドには制限がある
- 大量のリクエストが来てスレッドが限界に達することがある
	- スレッドが限界に達すると、処理できないリクエストは待ち状態になる

## イベントループ
- Node.jsで採用されている形式
- メインの処理とバックグラウンドの処理にわかれる
	- メインスレッドは処理待ちのキューになっており、一つしかない
		- スレッドがひとつしかないのでシングルスレッドとも呼ばれる	
- メインスレッドではEvent loopと呼ばれるループを回し、キューに登録されたリクエストをさばいている
	- ループ時にキューにリクエストがあると、バックグラウンドの処理を行う
	- ループが終わった時に終わった処理を検出できる
		- ただし、どの処理が行われたかは判別できない
	- 前の処理を行うまで処理を待つことが無いため、スレッドを新しく立ち上げる必要がないため高速に処理を行える
- ノンブロッキングな書き方をする必要がある
	- Event loopで処理を行うため、ループをブロックしない（ノンブロッキング）ようなプログラミングをする必要がある

# Hello World
## 対話環境で実行

```
$ node # 対話環境の立ち上げ
> console.log("hello world");
hello world
undefined
> .help # 使えるコマンドを参照
> .exit # 対話環境から抜ける
```

### 注意点
- Javascriptの基本的な命令はほぼ使える
- ただし、Node.jsでは実行環境がブラウザでないため、WindowやDOMに関する命令は使えない

## ファイルからの実行
カレントディレクトリに以下のファイルを設置

```node:hello.js
console.log("hello world");

```

コマンドラインから実行

```
$ node hello.js
hello world
```

# ノンブロッキングな処理とは？
## ノンブロッキングな書き方
DBアクセスやファイルへの書き込みのような時間の掛かりそうな処理は、次の処理をブロックしないよう書く必要がある。
具体的には、コールバック関数で処理を行う関数を渡すことで実装する。

```javascript:hello.js
// setTimeout関数で時間のかかる処理を実装
// setTimeout関数に渡す関数は1秒後に実行されるコールバック関数になっている
setTimeout(function() {
	console.log("hello");
}, 1000);
console.log("world");
```

これを実行すると、worldが先に表示される。

```
$ node hello.js
world
hello
```

## ノンブロッキングでない書き方
無理やり時間のかかる処理を行ってみる。

```javascript:hello.js
var start = new Date().getTime();
while (new Date().getTime() < start + 1000);
console.log("world");
```

実行すると、1秒後にworldが表示される。

```
$ node hello.js
world # 1秒後に表示される
```

このように、他の処理をブロックする処理を書いてしまうとすべての処理に影響が出るため注意する必要がある。