ども、@kimihom です。
今回は Node.js の Express を使った場合の非同期処理のスマートな対応方法をご紹介する。
Node.js の非同期処理の重要性
簡単な比較をすると、Ruby では非同期処理をほとんどしない代わりに、それぞれのリクエストの一連の処理がが終わるまでサーバーはそのために仕事をする。例えば、DB の読み書きの処理は ActiveRecord を使うが、そこで DB との接続をして処理が終わるまでサーバーの一つのリソース(プロセス)は占有されることになる。これはこれでシンプルなコーディングができるので良いのだけど、処理効率という観点ではあまりスマートな方法ではないと言われている。
Node.js でプログラムを書いていると、DB処理を含めたあらゆる処理が非同期となる。これによってより多くの処理を1つのサーバーで処理することが可能になる。しかし、JavaScript 特有の大量 function
ネストが続くコールバック地獄が頻繁に発生する。
さて、Express ではこのコールバック地獄を防ぐために next
という便利な引数が存在する。今回はこの next
についてご紹介しよう。
使い方
まず Express の基本的なルーティング処理は以下のような感じだ。
router.get('/', function(req, res, next) { res.render('index'); });
"/" へアクセスが来たら、index
の View をレンダリングせよという処理が書かれている。同じようにして、その下に router.get('/foo'...
と書けば、/foo
にアクセスした時の処理を書くことができる。んで、Express で書くときに意識したいのが、「リクエストが来たら、コードの上から順番にリクエスト処理がマッチするかを探しに行く」ということだ。そしてこれが next
を使う上で大切となる。
早速、先ほどの index
に非同期処理を噛ませてみよう。今回は JavaScript で定番の setTimeout
でレスポンスを遅らせてみる。
router.get('/', function(req, res, next) { setTimeout(next, 3000); // setTimeout(function() { next(); }, 3000); 上と同じ }); router.get('/', function(req, res, next) { res.render('index'); });
Express はリクエストが来たらコードが上から評価されるということを把握しておけば、"/" へアクセスが来たらまずは上のコードが実行され、next
によってその次にマッチする下のコードが実行されるという流れを理解できるはずだ。
Express の app.js に 404
や 500
の処理が最後にあるのはそのためである。最後の404の部分でマッチしてしまったら対応する定義が見つからなかったということで 404 をエラーを含めてnext
に渡す。next
の第一引数に エラーオブジェクトを入れておけば、他にマッチせず最終的に一番最後に定義されたエラーハンドリングの処理にマッチすることになる。
/// app.use ~~でルーティング定義 // 一番下に... // catch 404 and forward to error handler app.use(function(req, res, next) { var err = new Error('Not Found'); err.status = 404; next(err); }); // error handler app.use(function(err, req, res, next) { // set locals, only providing error in development res.locals.message = err.message; res.locals.error = req.app.get('env') === 'development' ? err : {}; console.error(err); // render the error page res.status(err.status || 500); res.render('error'); });
終わりに
今回は Express を使う上で大事なリクエストが来た際のコードが実行される順番について解説した。
next
の仕組みを理解することが、Express のコード実行の流れを理解することに繋がってくるので、これから Express を触ろうと思っている方は是非マスターしておいていただきたい。
Express をうまく使いこなせれば、多くの処理をハンドリングする高性能な Web アプリケーションを作ることができるので、シンプルな Web アプリケーションは Express で作ってみても良いかもしれない。