ユーザ用ツール

サイト用ツール


nodejs

node.js

node.jsはノンブロッキングI/Oとイベント駆動が特徴のJavaScript実行環境。イベントループ型のサーバを簡単に実装できる。Chromeブラウザと同じV8エンジンが使用されている。

バージョンとES feature

ブラウザと違って互換性を気にする必要はないので最新機能は遠慮なく使いましょう

node v4

  • デフォルト引数、分割代入、import以外のES2015機能が使えます。

node v6

  • import以外のES2015機能が使えます。

callbackに関するtips

callbackの第一引数はerrにする

絶対にエラーの発生しない処理だとしてもcallbackの第一引数はエラーが渡される想定のコードにすること。第一引数にnullを渡してcallbackを呼べし。

node, npmの多くのライブラリは第一引数でエラーを受け取る事を前提にしているので、こうすることで各種ライブラリ、モジュールとスムーズに連携できるようになる。

// これはだめ
function asyncFunc(callback) {
   setImmediate(function() {
      callback(true);
   });
}
// OK
function asyncFunc(callback) {
   setImmediate(function() {
      callback(null, true);
   });
}

非同期処理には必ずcallbackを

呼び出し元に結果を通知する必要のない非同期処理でも必ずcallbackを付ける(PromiseかEvent駆動ならcallbackなし可)

bad

function writeLogToDB(code, content) {
   // 失敗しても良い処理なので、呼び出しもとにエラーを通知しなくてもいい (← ダメです。だいたい後で通知したくなります)
   db.Log.insert({_id: code, content: content}, function(err) {
      err && mainLogger.error(err);
   });
}

good

function writeLogToDB(code, content, callback) {
   // callbackが渡されてなければデフォルトの処理を入れる
   if (!callback) callback = function(err) {
      err && mainLogger.error(err);   
   }
 
   db.Log.insert({_id: code, content: content}, function(err) {
      callback(err);
   });
}

callbackを2度呼ばない

function someAsyncFunc(callback) {
   // 途中省略...
   
   try {
       callback();
   } catch (e)
       callback(e);
   }
}

try側のcallback中に例外が発生するとcatch側のcallbackが呼ばれるので2回呼ばれてしまう。これによってデータ2重書き込み等の重大な問題が発生する恐れがあります。

require

require時に処理を走らせない

requireされるファイルは関数やクラスの定義のみにする。読み込んだだけでファイルの書き込み読み込み、サーバの起動、DB接続その他の処理を行ってはいけない。

Good

// hoge.js
var hoge = module.exports;
 
hoge.init = function() {
  // 何か初期化処理
}
 
 
// main.js
var hoge = require("./hoge");
hoge.init();              // 初期化処理の実行はrequireしたファイルで行う

Bad

// hoge.js
var hoge = module.exports;
 
hoge.init = function() {
  // 何か初期化処理
}
 
hoge.init();  
 
 
// main.js
require("./hoge");        // requireしただけでinitされてしまう

requireされるだけで何らかの処理が走るようにすると、起動時に予期せぬタイミングでinitが実行されたり、テストコードでinitが不要なのに呼ばれてしまったりする問題が発生します。

メモリ

--max-old-space-size

デフォルトで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

今度は2GBまで持ちました。が、こんなにメモリを使う実装の前に色々直しましょう

nodejs.txt · 最終更新: 2016/10/13 02:30 by nullpon