簡単に言えば、node.js は開発者が JavaScript 言語を使用してサーバーサイドのコードを作成できるようにするフレームワークです。つまり、記述された JavaScript コードは、ブラウザだけでなくローカル マシン上でも直接実行できます。実装の観点から見ると、Jaxer と Node.js は両方とも既存の JavaScript 実行エンジンを使用します。 Jaxer は Mozilla Firefox で使用される JavaScript エンジンを使用し、node.js は Google Chrome で使用される V8 エンジンを使用します。
node.js を始めましょう
node.js は、Linux、Windows、Macintosh などの主流のオペレーティング システムで実行できます。 Windows プラットフォームで node.js を実行する場合は、Cygwin または MinGW のサポートが必要です。以下では、一般的に使用される Windows プラットフォームを例として使用して説明します。まずCygwinをインストールする必要があります。インストール時に、gcc-g++、make、openssl、および Python パッケージを選択する必要があります。 gcc のバージョンは最新である必要があります。次に、「リソース」に示されているアドレスから、node.js バージョン 0.4.0 のソース コードをダウンロードします。ダウンロードして解凍した後、Cygwin で ./configure、make、make install などのコマンドを実行してコンパイルとインストールを行います。インストールが完了したら、node コマンドを直接実行して、node.js によって提供されるコマンド ラインを起動します。 JavaScript コードはコマンドラインに直接入力して実行できます。ノードserver.jsを介してJavaScriptファイルserver.jsを実行することもできます。
簡単な「Hello World」プログラムの例をコードリスト 1 に示します。ノード helloworld.js を通じて JavaScript ファイルを実行すると、コンソールに「Hello World」が出力されます。
リスト 1. node.js を使用した「Hello World」プログラム
process.stdout.write("Hello World");
コード リスト 1 のプロセスは、現在実行中の node.js プロセスとその属性 stdout を表します。プロセスの標準出力ストリームを表します。 write() メソッドを使用してストリームに文字列を書き込みます。コード リスト 1 からわかるように、JavaScript を使用して、標準出力ストリームなどのローカル システム上のリソースにアクセスできます。これは、node.js の強力な側面を反映しています。
node.js で実行できる JavaScript コードでは、コード リスト 1 で使用されるプロセス、以下で紹介するモジュールをロードするために使用される require() メソッド、および現在実行されている JavaScript __filename など、いくつかのグローバル オブジェクトを使用できます。ファイル名、現在実行中の JavaScript ファイルのディレクトリを示す __dirname、およびスケジュールされたタスクを実行するためにブラウザで使用されるものと同様の setTimeout() および setInterval() メソッド。
node.jsの基礎知識を紹介した後、node.jsのモジュール構造を紹介しましょう。
トップに戻る
モジュール構造
node.jsはCommonJSで定義されたモジュールシステムを使用します。さまざまな機能コンポーネントがさまざまなモジュールに分割されています。アプリケーションは、独自のニーズに応じて適切なモジュールの使用を選択できます。各モジュールは、いくつかのパブリック メソッドまたはプロパティを公開します。モジュールのユーザーは、モジュール内の実装の詳細を気にすることなく、これらのメソッドまたはプロパティを直接使用できます。システムによって事前に設定された複数のモジュールに加えて、アプリケーション開発チームはこのメカニズムを使用してアプリケーションを複数のモジュールに分割し、コードの再利用性を向上させることもできます。
モジュールの使用
node.js でモジュールを使用するのは非常に簡単です。モジュールを使用する前に、そのモジュールへの依存関係を宣言する必要があります。 JavaScript コードでグローバル関数 require() を直接使用して、モジュールをロードできます。たとえば、require("http") はシステムのプリセット http モジュールをロードできます。そして、require("./myModule.js") は、現在の JavaScript ファイルと同じディレクトリに myModule.js モジュールをロードするために使用されます。 require() を使用するパスが「/」で始まる場合、それはオペレーティング システム上のモジュール JavaScript ファイルの絶対パスとみなされます。これらのどちらにも当てはまらない場合、node.js は現在の JavaScript ファイルの親ディレクトリとその祖先ディレクトリの下にある node_modules ディレクトリを検索しようとします。たとえば、require("other.js") がディレクトリ /usr/home/my.js で呼び出された場合、node.js は次のファイルを順番に検索しようとします: /usr/home/node_modules/other.js, /usr/node_modules/other .js および /node_modules/other.js。
require() メソッドの戻り値は、モジュールによって公開されるパブリック JavaScript オブジェクトであり、使用可能なメソッドとプロパティが含まれます。コード リスト 2 は、モジュールの基本的な使用法を示しています。
リスト 2. モジュールの基本的な使用法
vargreetings = require("./greetings.js");
var msg =greetings.sayHello("Alex", "zh_CN");
process.stdout.write( msg);
コードリスト 2 に示すように、通常、require() メソッドの戻り値は変数に直接代入され、この変数は JavaScript コード内で直接使用できます。 greetings.js モジュールは、現在の JavaScript コードで直接使用される SayHello() メソッドを公開します。
独自のモジュールを開発
独自のモジュールを開発する基本的な作業は、モジュールに対応する JavaScript ファイルにモジュール関連のコードを記述することです。これにより、モジュールの内部処理ロジックがカプセル化されます。一般に、モジュールは通常、いくつかのパブリック メソッドまたはプロパティをユーザーに公開します。モジュールの内部コードは、これらのメソッドまたはプロパティを公開する必要があります。リスト 3 は、リスト 2 で使用したgreetings.js ファイルの内容を示しています。
リスト 3.greetings.js モジュールの内容
var language = {
"zh_CN" : "Hello,",
"en" : "Hello, "
}; language ) {
return language[ language ] || language["en"] + name;
};
リスト 4. HTTP プロキシ サーバー
var http = require("http");
var url = require("url");
http.createServer(function (req, res) {
var urlObj = url.parse(req.url, true); // プロキシ URL を取得します
var urlToProxy = urlObj.query.url;
if (!urlToProxy) { res.statuscode = 400; "URLが必要です。 )
};
for (ヘッダーの var キー) {
データ
});
.0.1");
console.log("プロキシ サーバーがポート 8088 で起動されました。 ");
プロキシ サーバー全体の実装は比較的単純です。まず、http モジュールの createServer() メソッドを使用して HTTP サーバーを作成し、次に listen() メソッドを使用して HTTP サーバーが特定のサーバーでリッスンするようにします。 createServer() ) メソッドは、HTTP リクエストの応答メソッドです。実際、コード リスト 4 の HTTP サーバー作成部分は、コード リスト 5 と同等です。実装方法は
リスト5. イベント機構を利用したHTTPサーバー作成方法
var server = http.createServer();
server.on("request", function(req, res) {
}) ;
リクエスト処理メソッドでは、http.get() メソッドを通じてプロキシ URL のコンテンツを取得します。ここでも、pres.on("data", function(chunk) {}) が使用されます。 pres の data イベントに処理メソッドが追加されます。このメソッドの機能は、取得したコンテンツを元の HTTP リクエストの応答に書き戻すことです。これは、開発時にも同様です。 node.js では、イベント処理メソッドとコールバック メソッドを使用するシナリオが頻繁に発生します。
node.js のイベント駆動メカニズムを紹介した後、一般的に使用されるモジュールをいくつか示します。
トップに戻る
。
node.js は、ネットワークとファイル システムの操作に関連する多くのモジュールをデフォルトで提供します。これらのモジュールは、前に説明したように、サーバー側アプリケーションを構築するための基礎となります。 、node.js はイベント駆動型のアーキテクチャを採用しており、そのモジュールの多くはさまざまなイベントを生成します。イベントを生成できるすべてのイベント処理メソッドは、モジュール ユーザーによって追加できます。オブジェクトはすべて、イベント モジュール内の EventEmitter クラスのインスタンスです。 EventEmitter クラスのメソッドは、次のようにイベントの生成と処理に関連しています:
addListener(event,listener) および on(event,listener): これら 2 つのメソッドは、イベント処理メソッドのリスナーを特定のイベント イベントに追加するために使用されます。
once(event,listener): このメソッドは、イベントイベントに対して 1 回だけ実行される処理メソッドのリスナーを追加します。処理メソッドは一度実行すると削除されます。
removeListener(event,listener): このメソッドは、イベントイベントの処理メソッドリスナーを削除するために使用されます。
emit(event, [arg1], [arg2], [...]): このメソッドは、イベントイベントを生成するために使用されます。イベント名の後のパラメータは、対応するイベント処理メソッドに渡されます。
コード リスト 6 は、イベント モジュールの使用例を示しています。
リスト6. イベントモジュールの使用例
var events = require("events");
var Emitter = new events.EventEmitter();
emiter.on("myEvent", function(msg) {
console. log(msg);
});
Emitter.emit("myEvent", "Hello World.");
イベント モジュールに特殊なイベント エラーがあります。 EventEmitter は、エラーが発生したときにこのイベントを生成します。このイベントに対応する処理方法がない場合、デフォルトの動作では、エラー メッセージを出力した後、プログラムが自動的に終了します。したがって、エラー イベントのハンドラーを常に追加するように注意してください。
ストリーム
node.js には、ファイル システム、HTTP リクエストと応答、TCP/UDP 接続などを含む、さまざまなデータ ストリームがあります。これらのストリームはすべて EventEmitter のインスタンスであるため、さまざまな異なるイベントを生成できます。ストリームは、読み取り専用ストリーム、書き込み専用ストリーム、読み取り/書き込みストリームの 3 つのタイプに分類できます。
読み取り可能なストリームは主に 4 つのイベントを生成します:
data: このイベントは、ストリーム内のデータが読み取られるときに生成されます。
end: このイベントは、ストリーム内に読み取るデータがない場合に生成されます。
error: このイベントは、データの読み取り中にエラーが発生した場合に生成されます。
close: このイベントは、ストリームが閉じられたときに生成されます。
上記のイベントに加えて、現在の読み取り可能なストリームを別の書き込み可能なストリームに接続するために使用できる Pipe() メソッドもあります。読み取り可能ストリーム内のデータは、書き込み可能ストリームに自動的に書き込まれます。
書き込み可能なストリームで最も一般的に使用されるメソッドは、write() と end() です。 write() メソッドはストリームにデータを書き込むために使用され、end() は書き込み操作を終了するために使用されます。
バイナリ データを表すために、node.js は Buffer クラスを使用してバイナリ データを操作するデータ バッファーを表します。 Buffer クラスは、データを配列の形式で内部に格納します。バッファーのサイズは、作成後に変更することはできません。 Buffer クラスのインスタンスは、JavaScript の文字列型との間で変換可能です。変換時にエンコード形式を指定する必要があります。 Buffer の先頭から末尾までの内容は、Buffer クラスの toString(encoding, start, end) メソッドによるエンコードによってエンコードされた文字列に変換できます。サポートされているエンコード形式は、ascii、utf8、base64 です。バッファは、 new Buffer(str, encoding) を介して文字列 str で初期化できます。 write(string, offset, encoding) は、バッファ内の offset から始まる位置に、エンコーディング形式のエンコーディングで文字列 string を書き込むために使用されます。
ネットワーク操作
node.js は、ネットワーク サーバーとクライアントを実装できる、TCP、UDP、HTTP などのネットワーク操作に関連するいくつかのモジュールを提供します。
TCPプロトコルに関連する実装はnetモジュールにあります。 TCP サーバーは、このモジュールの createServer(connectionListener) メソッドを通じて作成できます。パラメータconnectionListenerはクライアントがサーバに接続する際の処理メソッドであり、connectイベントの処理に相当します。 TCP サーバーは、クラス Server のインスタンスです。 listen メソッドを使用すると、サーバーは指定されたポートで listen できます。
既存の TCP サーバーに接続する場合は、createConnection(port, host) メソッドを使用して、指定したホスト host のポート port に接続できます。このメソッドの戻り値は、ソケット接続を表す Socket クラスのインスタンスです。 Socket クラスのインスタンスを取得した後、write() メソッドを通じて接続にデータを書き込むことができます。この接続からデータを取得する場合は、データ イベント処理メソッドを追加できます。
コード リスト 7 は、式計算用の単純な TCP サーバーを示しており、テストのために Telnet コマンドを介してこのサーバーに接続できます。
リスト 7. 単純な式計算サーバー
var net = require("net");
var server = net.createServer(function(socket) {
ソケット.setEncoding("utf8");
varbuffer = [ ], len = 0;
socket.on("data", function(data) { // クライアントデータを受信
if (data.charCodeAt(0) == 13) {
var expr =buffer.join(" " );ソケット.write("間違った表現です。");
express.buffer.push(data);
server.listen(8180, "127.0.0.1");
console.log("サーバーはポート 8180 で起動されました。 ");
TCP サーバーに加えて、http モジュールと https モジュールはそれぞれ HTTP サーバーと HTTPS サーバーを実装できます。dgram は UDP/データグラム ソケット接続を実装でき、モジュール tls はセキュア ソケット接続 (SSL) を実装できます。これらのモジュールはすべて、tcp モジュールと同様に使用されます。
ファイルシステム
node.jsのfsモジュールはローカルファイルシステムの操作に使用されます。 fs モジュールで提供されるメソッドを使用して、読み取り、書き込み、名前変更、ディレクトリの作成と削除、ファイル メタデータの取得などの基本的なファイル操作を実行できます。ファイルを操作する各方法には、同期バージョンと非同期バージョンの両方があります。非同期バージョンの操作では、常にコールバック メソッドが最後のパラメータとして使用されます。操作が完了すると、コールバック メソッドが呼び出されます。コールバック メソッドの最初のパラメータは、操作中に発生する可能性のある例外のために常に予約されています。操作が正しく成功した場合、最初のパラメータの値は null または unknown になります。同期操作バージョンのメソッド名には、対応する非同期メソッドの後に接尾辞として Sync が追加されます。たとえば、非同期 rename() メソッドの同期バージョンは renameSync() です。 fs モジュールの一般的なメソッドのいくつかを以下に示します。ここでは、非同期操作バージョンのみを紹介します。
rename(path1, path2): パス path1 で表されるディレクトリまたはファイルの名前をパス path2 に変更します。
truncate(fd, len): ファイル記述子 fd に対応するファイルの長さを len に切り詰めます。
chmod(path, mode): path で表されるディレクトリまたはファイルの権限を mode に変更します。
stat(path): path で表されるディレクトリまたはファイルのメタデータを取得します。メタデータは Stats クラスを使用して表現されます。
open(path, flags, mode): パス path で表されるファイルを開きます。ファイル記述子はコールバックメソッドで取得できます。
read(fd,buffer,offset,length,position): 指定されたファイル記述子fdで表されるファイル内の位置positionから開始してlengthバイトのデータを読み取り、開始位置のoffsetから開始してバッファbufferに格納する。実際に読み取られたバイト数はコールバックメソッドで取得できます。
readFile(filename, encoding): ファイル filename の内容をエンコード形式のエンコーディングで読み取ります。ファイルの内容はコールバックメソッドで取得できます。
writeFile(filename, data, encoding): データ data をエンコード形式エンコーディングでファイル filename に書き込みます。ファイル自体を直接操作する上記の方法に加えて、ファイルをストリームに変換することもできます。 createReadStream(path, options) と createWriteStream(path, options) は、それぞれファイルから読み取り可能および書き込み可能なストリームを作成するために使用されます。パラメータ path はファイルへのパスを表し、options はファイルの読み取りまたは書き込み時のオプションを表す JavaScript オブジェクトです。
単純な HTTP 静的ファイル サーバーの実装をコード リスト 8 に示します。
リスト 8. HTTP 静的ファイルサーバー
var http = require("http"),
fs = require("fs"),
path = require("path"),
url = require("url");
var server = http.createServer(function(req, res) {
var pathname = url.parse(req.url).pathname;
var filepath = path.join("/tmp", "wwwroot", pathname) ;
var stream = fs.createReadStream(filepath, {flags : "r", encoding : null});
stream.on("error", function() {
res.writeHead(404);
res.end( );
});
stream.pipe(res);
});
server.on("error", function(error) {
console.log(error);
});
server.listen(8088 , "127.0.0.1");
コード リスト 8 に示すように、まず HTTP リクエストのパスをサーバー上のファイル パスに変換し、次にファイルから読み取り可能なストリームを作成し、最後に Pipe() メソッドを使用します。 HTTP リクエストの応答に渡されたファイルのデータ ストリームを変換します。
補助モジュール
上記で紹介した一般的なモジュールに加えて、node.js はいくつかの補助モジュールも提供します。
モジュールパスは、ファイルシステム上のパスを処理するために使用されます。このモジュールの join() は、複数のパスを接続して完全なパスを形成するために使用されます。たとえば、join("/usr", "home", "test/index.html") の結果は、パス /usr/home/test/index.html になります。 Normalize() は、パスを正規化し、冗長な「/」を削除し、「..」と「.」を処理するために使用されます。 solve([from ...], to) メソッドは、指定されたパスの絶対パスを取得するために使用されます。 to が絶対パスでない場合は、絶対パスが得られるまで前のパラメータを右から左に追加します。最終的に絶対パスが取得できない場合は、現在の作業ディレクトリを追加してください。現在の作業ディレクトリが /usr/home であると仮定すると、resolve("test", "index.html") の戻り結果は /usr/home/test/index.html になります。 dirname() メソッドは、パスのディレクトリ部分を取得するために使用されます。たとえば、dirname("/usr/home/index.html") の戻り結果は /usr/home です。 Basename() は、パスの最後の部分を取得するために使用されます。たとえば、basename("/usr/home/index.html") の戻り結果は、index.html です。 extname() は、パスのファイル拡張子部分を取得するために使用されます。たとえば、extname("/usr/home/index.html") の戻り結果は .html です。
モジュール URL は URL を解析するために使用されます。 parse(urlStr, parseQueryString) メソッドは、URL 文字列 urlStr をホスト名、ポート、パスなどのいくつかの部分に解析するために使用されます。このメソッドの戻り値は、プロトコル、ホスト名、ポート、パス名、クエリなどのプロパティを含む JavaScript オブジェクトです。パラメータ parseQueryString の値が true の場合、URL に含まれるクエリ文字列部分も解析されます。 format(urlObj) メソッドは parse() メソッドの逆で、JavaScript オブジェクトから URL 文字列を構築するために使用されます。
モジュール querystring は、URL 内のクエリ文字列を処理するために使用されます。 stringify(obj) メソッドは、JavaScript オブジェクト obj をクエリ文字列形式に変換するために使用されます。たとえば、stringify({a : 1, b : "good"}) は a=1&b=good を返します。 parse(str) は、クエリ文字列を JavaScript オブジェクトに解析するために使用されます。
モジュール vm を使用して JavaScript コードを実行できます。 runInThisContext(code) メソッドは、JavaScript コードの一部を実行し、その結果を返すために使用されます。このメソッドを通じて実行される JavaScript コードは、現在のコードのスコープにアクセスできません。 runInNewContext(code, [sandbox]) メソッドは、JavaScript コードの実行にも使用されます。 runInThisContext() とは異なり、このメソッドで実行される JavaScript コードは、サンドボックス オブジェクトをグローバル オブジェクトとして使用します。たとえば、runInNewContext("a + 3", {a : 4}) の戻り結果は 7 です。 createScript(code) メソッドは JavaScript コードをプリコンパイルするために使用されますが、すぐには実行されません。このメソッドの戻り値は Script オブジェクトです。このオブジェクトには、runInThisContext() と runInNewContext([sandbox]) という 2 つのメソッドもあります。これらは、上記の 2 つのメソッドと同様の意味を持ちます。
モジュール os は、基礎となるオペレーティング システムに関連する情報を提供します。 hostname() はオペレーティング システムのホスト名を取得するために使用され、type() はオペレーティング システムの種類を取得するために使用され、release() はオペレーティング システムのリリース バージョン番号を取得するために使用されます。システムの実行時間を秒単位で取得するには、;cpus() を使用して CPU 関連の情報を取得します。 freemem() と totalmem() は、それぞれシステムの合計メモリと利用可能なメモリを取得するために使用されます。
モジュール util は、一般的に使用される補助メソッドをいくつか提供します。 debug(string) メソッドは、標準エラー ストリームに情報を出力するために使用されます。 log(string) メソッドは、タイムスタンプ付きの情報を標準出力ストリームに出力するために使用されます。 Inspection(object, showHidden, Depth) メソッドは、オブジェクトの内部構造を出力するために使用されます。 showHidden パラメータは、オブジェクトの非表示属性を表示するかどうかを示します。表示される階層のデフォルト値は 2 です。 Inherits(constructor, superConstructor) メソッドは、JavaScript でプロトタイプベースの継承メカニズムを実装するために使用されます。
node.js によって提供される一般的なモジュールを紹介した後、node.js の使用法を示す完全な例を次に示します。
トップに戻る
インスタンス分析
この例で実装される機能は、サーバーのメモリ使用状況、つまりメモリ占有率を動的に監視することです。サーバー上のメモリ使用量の取得は比較的簡単で、OS モジュールによって提供されるメソッド、つまり freemem()/totalmem() を使用するだけです。メモリ占有をリアルタイムで監視するには、サーバーはブラウザにデータをリアルタイムで送信する必要があります。ここでの最良の実装は、HTML 5 で導入された WebSocket 仕様です。この仕様は、Firefox 4 や Google Chrome などの新しいブラウザーでサポートされています。同時に、サーバー側もこの仕様をサポートする必要があります。 Socket.IO は、サーバー側およびブラウザー側のコードを含む、node.js 上の WebSocket 仕様のサポートを提供します。コード リスト 9 は、Socket.IO を使用するサーバー側のコードを示しています。
リスト 9. メモリ使用量を監視するサーバー側のコード
var io = require('./socket.io');
var io = io.listen(server);
io.on("connection", function (client){
setInterval(function() {
client.send(os.freemem() / os.totalmem());
}, 500);
});
コード リスト 9 では、サーバーはノード An です。 .js の HTTP サーバー オブジェクト。一般的な HTTP リクエストに応答するために使用されます。 Socket.IO は、node.js HTTP サーバーからのリクエストをインターセプトし、一部のリクエストを処理のために Socket.IO に渡すことができます。ここでの処理ロジックは、クライアントが接続すると、サーバーのメモリ使用量が 500 ミリ秒ごとにクライアントに送信されるというものです。コード リスト 10 は、ブラウザ側の HTML および JavaScript コードを示しています。
リスト 10. メモリ使用量を監視するブラウザ側のコード