ユーザ用ツール

サイト用ツール


nodejs

差分

このページの2つのバージョン間の差分を表示します。

この比較画面へのリンク

次のリビジョン
前のリビジョン
nodejs [2011/09/28 08:38] – /node.jsから移動 nullponnodejs [2016/10/13 02:30] (現在) – [--max-old-space-size] nullpon
行 1: 行 1:
 ====== node.js ====== ====== node.js ======
-[[http://nodejs.org/|node.js]]はノンブロッキングI/Oとイベント駆動が特徴のJavaScript実行環境。イベントループ型のサーバを簡単に実装できる。Googleが開発し、Chromeブラウザと同じV8エンジンが使用されている。+[[http://nodejs.org/|node.js]]はノンブロッキングI/Oとイベント駆動が特徴のJavaScript実行環境。イベントループ型のサーバを簡単に実装できる。Chromeブラウザと同じV8エンジンが使用されている。
  
-node.jsはCommonJSというサーサイドJavaScriptの仕様にしたがっている。+===== ージョンとES feature =====
  
-===== HTML5 の Server-Sent Events を実装しる =====+ブラウザと違っ互換性を気にす必要はないので最新機能は遠慮なく使いましょう
  
-[[http://d.hatena.ne.jp/paulownia/20110110/1294671579|node.jsでServer-Sent Eventsを試す - nullpo.printStackTrace();]]+node v4
  
-バ側を node.js 実装してる。+  * デフォルト引数、分割代入、import以外のES2015機能が使えます。 
 + 
 +node v6 
 + 
 +  * import以外のES2015機能が使えます。 
 + 
 +===== callbackに関するtips ===== 
 + 
 +==== callbackの第一引数はerrにする ==== 
 + 
 +絶対にエラの発生しない処理だとしてもcallbackの第一引数はエラーが渡される想定のコードにすること。第一引数にnull渡してcallbackを呼べし。 
 + 
 +node, npmの多くのライブラリは第一引数エラーを受け取る事を前提にしているので、こうすることで各種ライブラリ、モジュールとスムーズに連携できるようになる。
  
-generator.js 
 <code javascript> <code javascript>
-// EventEmitterを取得 +// これはだめ 
-var events = require("events"); +function asyncFunc(callback{ 
-var emitter = new events.EventEmitter();+   setImmediate(function() { 
 +      callback(true); 
 +   }); 
 +
 +</code>
  
-// EventEmitterを拡張 +<code javascript> 
-emitter.id = 0; +// OK 
-emitter.data = ""; +function asyncFunc(callback) { 
-emitter.start = function() { +   setImmediate(function() { 
-    var chars = "node.js"; +      callback(nulltrue); 
-    var self = this; +   }); 
-    setInterval(function() { +} 
-        var pos = Math.floor(Math.random() * chars.length * 2);  +</code>
-        if (pos < chars.length) { +
-            self.id++; +
-            self.data = chars.charAt(pos); +
-            // generatedイベントとして登録されたリスナを呼び出す +
-            self.emit("generated", self.idself.data);   +
-        } +
-    }, 1000); +
-};+
  
-// module.exportsに設定されたオブジェクトがrequire戻り値とな。 + 
-module.exports = emitter+==== 非同期処理には必ずcallbackを ==== 
 + 
 +呼び出し元に結果を通知する必要のない非同期処理でも必ずcallbackを付ける(PromiseかEvent駆動ならcallbackなし可) 
 + 
 +bad  
 + 
 +<code javascript> 
 +function writeLogToDB(code, content) { 
 +   // 失敗しても良い処理なで、呼び出しもにエラーを通知しくてもいい (← ダメですだいたい後で通知したくなります) 
 +   db.Log.insert({_id: code, content: content}, function(err) { 
 +      err && mainLogger.error(err); 
 +   }); 
 +}
 </code> </code>
  
-server.js+good 
 <code javascript> <code javascript>
-var http require("http"+function writeLogToDB(code, content, callback) { 
-http.createServer(handler).listen(8124);+   // callbackが渡されてなければデフォルトの処理を入れる 
 +   if (!callback) callback function(err{ 
 +      err && mainLogger.error(err);    
 +   } 
 +    
 +   db.Log.insert({_id: code, content: content}, function(err) { 
 +      callback(err); 
 +   }); 
 +
 +</code>
  
-var generator require("./generator"+==== callbackを2度呼ばない ====
-generator.start();+
  
-function handler(req, res) {+<code> 
 +function someAsyncFunc(callback) { 
 +   // 途中省略... 
 +    
 +   try { 
 +       callback(); 
 +   } catch (e) 
 +       callback(e); 
 +   } 
 +
 +</code> 
 + 
 +try側のcallback中に例外が発生するとcatch側のcallbackが呼ばれるので2回呼ばれてしまう。これによってデータ2重書き込み等の重大な問題が発生する恐れがあります。 
 + 
 + 
 +===== require ===== 
 + 
 +==== require時に処理を走らせない ==== 
 + 
 +requireされるファイルは関数やクラスの定義のみにする。読み込んだだけでファイルの書き込み読み込み、サーバの起動、DB接続その他の処理を行ってはいけない。 
 + 
 +Good 
 +<code javascript> 
 +// hoge.js 
 +var hoge = module.exports;
  
-    function response(id, data) { +hoge.init = function() { 
-        generator.removeListener("generated", arguments.callee); +  // 何か初期化処理
-         +
-        res.writeHead(200,+
-            "Content-type": "text/event-stream" +
-        }); +
-        res.write("id:" + id + "\n"); +
-        res.write("data:" + data + "\n"); +
-        res.write("retry: 1000"); +
-        res.end(); +
-         +
-    } +
-    generator.on("generated", response);+
 } }
 +
 +
 +// main.js
 +var hoge = require("./hoge");
 +hoge.init();              // 初期化処理の実行はrequireしたファイルで行う
 </code> </code>
  
-クライアント側のJavaScript+Bad 
 <code javascript> <code javascript>
-var source new EventSource(url)+// hoge.js 
-source.onmessage = function(event) { +var hoge module.exports
-  // データ受信時の処理を書く + 
-  // event.data でサーバから送られてきたデータを取得できる+hoge.init = function() { 
 +  // 何か初期化処理
 } }
 +
 +hoge.init();  
 +
 +
 +// main.js
 +require("./hoge");        // requireしただけでinitされてしまう
 </code> </code>
  
-実装サプルGit取得ます。+requireされるだけで何らかの処理が走るようにすると、起動時に予期せぬタイミグでinitが実行されたりテストコードinitが不要なのに呼ばれてしまったりする問題が発生します。 
 + 
 +===== メモリ ===== 
 + 
 +==== --max-old-space-size ==== 
 +<markdown> 
 +デフォルト1.5GB以上のメモリを確保しようとするとクラッシュします。ひたすらメモリを食いつぶしていくコードを実行すると… 
 + 
 +``` 
 +<--- Last few GCs ---> 
 + 
 +   84313 ms: Mark-sweep 1389.5 (1456.5) -> 1396.1 (1456.5) MB, 844.5 / 0 ms [allocation failure] [GC in old space requested]. 
 +   85167 ms: Mark-sweep 1396.1 (1456.5) -> 1398.0 (1456.5) MB, 854.0 / 0 ms [allocation failure] [GC in old space requested]. 
 +   86028 ms: Mark-sweep 1398.0 (1456.5) -> 1387.1 (1456.5) MB, 860.4 / 0 ms [last resort gc]. 
 +   86898 ms: Mark-sweep 1387.1 (1456.5) -> 1389.0 (1456.5) MB, 870.4 / 0 ms [last resort gc]. 
 + 
 + 
 +<--- JS stacktrace ---> 
 + 
 +==== JS stack trace ========================================= 
 + 
 +Security context: 0x2e7afd4b4629 <JS Object> 
 +    1: nextTick [node.js:~473] [pc=0x1cfdf0766f8e] (this=0x3bb898d1c211 <a process with map 0x31a25a8113b9>,callback=0x1d8be6ffc341 <JS Function afterWrite (SharedFunctionInfo 0x1d8be6f1c359)>
 +    2: arguments adaptor frame: 5->1 
 +    3: onwrite(aka onwrite) [_stream_writable.js:~314] [pc=0x1cfdf075ee02] (this=0x2e7afd4041b9 <undefined>,stream=0x1d8be6fb5d81 <a WriteStream with map 0xbb33c7202f... 
 + 
 +FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory 
 +zsh: abort      node hoge.js 
 +``` 
 + 
 +上限を増やすには 
 + 
 +``` 
 +$ node --max-old-space-size=2048 hoge.js 
 +``` 
 + 
 +これを実行すると… 
 + 
 +``` 
 +<--- Last few GCs ---> 
 + 
 +  183271 ms: Scavenge 2044.5 (2114.7) -> 2044.5 (2114.7) MB, 0.8 / 0 ms (+ 1.4 ms in 1 steps since last GC) [allocation failure] [incremental marking delaying mark-sweep]. 
 +  184563 ms: Mark-sweep 2044.5 (2114.7) -> 2035.4 (2114.7) MB, 1291.3 / 0 ms (+ 2.3 ms in 2 steps since start of marking, biggest step 1.4 ms) [last resort gc]. 
 +  185914 ms: Mark-sweep 2035.4 (2114.7) -> 2036.5 (2114.7) MB, 1351.8 / 0 ms [last resort gc]. 
 + 
 + 
 +<--- JS stacktrace ---> 
 + 
 +==== JS stack trace ========================================= 
 + 
 +Security context: 0x1f9ab28b4629 <JS Object> 
 +    1: $toString(aka ToString) [native runtime.js:~563] [pc=0x3fdefe2641cb] (this=0x1f9ab28919c1 <JS Object>,i=0xecfd57afc99 <Number: 1.95963e+09>
 +    2: a(aka a) [/Users/nullpon/hoge.js:14] [pc=0x3fdefe249ab8] (this=0x1f9ab28041b9 <undefined>
 +    3: /* anonymous */ [/Users/nullpon/hoge.js:20] [pc=0x3fdefe247d7d] (this=0x3c41316b29c9 <an Object with map 0x24b594a087d1>,exports=0x3c41316b29c9 <a... 
 + 
 +FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory 
 +zsh: abort      node --max-old-space-size=2048 hoge.js 
 +```
  
-  $ git clone http://dev.paulownia.jp/git/sse.git +今度は2GBまで持ちました。が、こんなにメモリを使う実装の前に色々直しましょう 
-  $ cd sse +</markdown>
-  $ node server.js+
nodejs.1317199121.txt.gz · 最終更新: 2011/09/28 08:38 by nullpon