目次
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まで持ちました。が、こんなにメモリを使う実装の前に色々直しましょう