node-js

サーバサイドJavaScriptの動向とNode.js

前回は、サードパーティアプリとエコシステムを構築する Web APIの実例についてまとめた。ここでは、サーバサイドJavaScriptの動向と共通APIのCommonJS、そしてNode.jsについて解説する。

1 サーバサイドJavaScriptの動向

サーバサイドJavaScriptは一度生まれて廃れた経緯がある。そして現在、再び注目され始めている。その要因は2つあり、1つはJavaScript自体の言語としての盛り上がりで、もう1つはJava仮想マシン(JVM)上で動くJVM言語の盛り上がりである。JVM上に移植されたJavaScript実装のRhinoの存在がサーバサイドJavaScriptを後押ししている。

そしてNode.jsの登場である。Node.jsは高速JavaScript処理系のv8をベースに非同期処理でスケーラブルなサーバを記述できる環境である。さらに、クラウドコンピューティングの中心であるグーグル社のGoogle Apps Scriptも出てきている。

 

2 CommonJS

CommonJSとは

CommonJSはサーバサイドJavaScriptのための標準API策定を目指した活動から始まり、後にサーバサイドより広範囲まで視野に入れて発展した。CommonJSと連動する形でJSGIという規格もある。CommonJSはファイル操作など基本機能のAPIで、JSGIはWebアプリ用のAPIである。

 

CommonJSの動向

現在多くのライブラリやフレームワークがCommonJS準拠に向かっている。Node.jsもその1つである。当面、サーバサイドJavaScriptの標準APIは、力のある実装(Node.jsやunderscore.jsなど)やクライアントサイドからの流入(jQueryやHTML5関連のAPIなど)が事実上の標準APIになり、これらをCommonJSが取り込んでいく流れになるだろう。

 

モジュール機能

  • モジュール機能が必要な背景:インクルードによる複数ファイル連結はファイル数が増えた場合の管理が面倒。これを解決するための仕組みがCommonJSのモジュール規格
  • モジュールの具体例:CommonJSモジュールはデフォルトでグローバルの名前空間を汚染しない。モジュールとして読まれる側には最初からexportsmoduleという2つのオブジェクトが存在する。exportオブジェクトのプロパティ名がモジュールの外部に公開される名前である。moduleオブジェクトにはidとurlの2つの読み取り専用プロパティがある
  • モジュールを使うコード:モジュールを使うにはrequire関数を使う。require関数に渡すモジュール名から対応するファイルを探す方法は実装依存である。指定したモジュールが見つからない場合、require関数はError例外オブジェクトを投げる
  • モジュールの応用:require関数(関数オブジェクト)にはmainとpathsの2つのプロパティがある。mainプロパティはmoduleオブジェクトと同一判定することで、そのファイルが直接実行されたのかモジュールとして読み込まれたかを判定できる。pathsプロパティ値はモジュールを探すファイルパスの配列である

 

3 Node.js

Node.jsの概要

Node.jsは非同期処理を特徴とする処理系である。Node.jsの特徴は以下の4つ。

  • JavaScript処理系はv8(ネットワーク周りなどはlibevやlibeioなど既存Cライブラリを利用)
  • 非同期処理の汎用イベントループを提供する処理系
  • 対話的シェル機能もあるコマンドラインツールが付属
  • パッケージシステムによる拡張性

Node.jsでWebアプリを作る場合、Node.jsでHTTPサーバのレイヤからWebアプリサーバのレイヤからWebアプリサーバのレイヤまで完結できる。ここでは主にNode.jsでWebアプリを作る前提だが、メールサーバでもネームサーバでもコマンドラインツールでも(GUIライブラリとのバインディングがあれば)GUIツールでも、作ることができる。

  • サードパーティモジュール:http://github.com/ry/node/wiki/modules
  • Node.jsのAPI:http://nodejs.org/docs/latest/api/index.html
  • 非同期処理とノンブロッキング処理:読み書きの処理を裏で動かすことと待ち状態にならないこと
  • Node.jsの非同期処理の動作:書き込みと読み込みには非対称性がある。書き込みはメソッド呼び出しで行う、ノンブロッキングなメソッド(関数)。読み込みに対応する(readのような)関数やメソッドは存在しない
  • モジュール:CommonJSモジュール規格に従う
  • module.exports

 

nodeコマンド

利用者に見えるNode.jsの実体はnodeという名前のコマンドである。引数なしでnodeコマンドを起動すると対話的シェルとして起動する。

  • ファイルの実行:nodeコマンドのコマンドライン引数にファイル名を渡すとファイルの中身をJavaScriptコードとして実行する

 

npmとパッケージ

Node.jsにはNode Package Manager(npm)と呼ばれるパッケージシステムがある(http://npmjs.org)。モジュールとパッケージの関係は、前者がNode.js自体が提供するプログラムの分割統治を助ける言語機能で、後者が配布のための仕組みである。

 

consoleモジュール

consoleオブジェクトは、内部的にはconsoleオブジェクトである。標準でロードされるモジュールなので明示的なvar console = require(‘console’)の行は不要である。consoleモジュールの関数の例はlog()、info()など。

 

utilモジュール

consoleオブジェクトと並んでデバッグに便利なのがutilモジュールである。

 

processオブジェクト

processオブジェクトはホストオブジェクトの1つである。デフォルトで存在するグローバル変数processで参照できる。プロパティ一覧はconsole.dir(process)で表示できる。

 

グローバルオブジェクト

Node.jsにはグローバル変数globalがデフォルトで存在する。常にグローバルオブジェクトを参照する変数である。

 

Node.jsプログラミングの概要

  • コールバック関数:非同期処理のためにコールバック関数を多用する
  • イベントループ:イベント待ちのコードを書くとスクリプトが暗黙にイベントループに入る
  • イベント処理の形:イベントにイベントハンドラを追加するのが基本

 

イベントAPI

イベントハンドラ(イベントリスナ)とはイベントに反応して呼ばれるコールバック関数である。イベントの発生を、イベントの発行(emit)や発火(fire)と呼ぶ。イベントの発行元オブジェクトをイベントソース(オブジェクト)と呼ぶ。各イベントはイベントソースで一意な文字列(イベント名)で識別される。イベントとイベントハンドラの対応は1対多である。

  • EventEmitterクラス:Node.jsのイベントソースはeventsモジュールのEventEmitterクラスを継承する。よく使うメソッドはイベントハンドラの追加メソッドと削除メソッドである。EventEmitterクラスのインスタンスオブジェクトはnewListenerイベントを発行する
  • イベントハンドラ内のthis参照:イベントソースオブジェクトを参照する。bindを使える
  • イベントハンドラ内で非同期処理を呼ぶときの注意:イベントハンドラ内で非同期な関数やメソッドを普通に呼ぶ
  • イベントドリブンプログラミングの鉄則:あらゆるイベントハンドラは(暗黙の)イベントループから呼ばれる。イベントハンドラ内で決してブロックしてはならない
  • 独自イベント:自作のオブジェクトをイベントソースにするためにutil.inspect関数を使うイディオムがある

 

バッファ

JavaScript以外のプログラミング言語にはいわゆる配列と呼ばれるデータ構造がある。一般に配列は特定の要素型の値を格納したメモリ領域である。

  • Bufferオブジェクトの生成:Bufferクラスのインスタンスオブジェクトはコンストラクタにサイズを渡して生成する
  • Bufferオブジェクトと文字列:Bufferオブジェクトから文字列値に変換するにはtoStringメソッドを使う。引数で文字エンコードを指定できる。エンコーディングは以下の4つ(ascii、utf8、base64、ucs2)
  • Bufferオブジェクトの要素のアクセス:数値のインデックスを使うブラケット演算子でアクセスできる。lengthプロパティでサイズを得られる
  • Bufferオブジェクトのメソッド
  • Bufferオブジェクトの注意

 

ストリーム

ストリームはデータを読み書きできる機能の抽象である。一般的な対象はファイルやネットワークだが、データの読み書きという共通の性質さえ持てば何でもストリームとして見なせる。Node.jsのストリームの機能はStreamクラスが担う。

  • ストリームと非同期処理:メソッド呼び出しだけでなくコールバック関数によるイベント処理も必要
  • 読み込みストリーム:最重要イベントはdataイベント。このイベントハンドラの引数に読み込みデータが渡る
  • 書き込みストリーム:基本はwriteメソッドの呼び出し
  • 標準入出力:processモジュールに標準入出力のストリームオブジェクトがある

 

最後に

サーバサイドJavaScriptは一度生まれて廃れた経緯がある。そして現在、再び注目され始めている。その要因の1つにNode.jsがあり、高速JavaScript処理系のv8をベースに非同期処理でスケーラブルなサーバを記述できる環境である。Node.jsの特徴はJavaScript処理系がv8、非同期処理の汎用イベントループを提供する処理系などである。

次回は、非同期処理実例、Express、MongoDBなど 実践Node.jsプログラミングについて解説する。

パーフェクトJavaScript (PERFECT SERIES 4)


「サーバサイドJavaScriptの動向とNode.js」への1件のフィードバック

  1. ピンバック: サーバサイドJavaScriptの動向とNode.js : ちゅどん道中記

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>