koa, co そして thunk について
Node の Web Framework としては Express が有名だが、
最近は、Node の ES6 実装に伴い、 ES6 の新しい機能を利用した koa という Web Framework が注目を集めている。
koa は ES6 の generators をフルに活用したインターフェイスが特徴で、
今までの JS に慣れている人間は度肝を抜かれること請け合いである。
下は、 koa で レスポンス時間を測るサンプルコードである。きもい
var koa = require('koa'); var app = koa(); // logger app.use(function *(next){ var start = new Date; yield next; var ms = new Date - start; console.log('%s %s - %s', this.method, this.url, ms); }); // response app.use(function *(){ this.body = 'Hello World'; }); app.listen(3000);
generators をつかってるのはわかるが、そもそもなんでこんなことになってるのか
その理由は、 koa の中で使われている co にある。
co は generators を利用したライブラリで、
非同期処理を同期処理っぽく書くことを可能にする。
下は、 co で HTTP リクエストを順番に実行するサンプルコードである。
var co = require('co'); var thunkify = require('thunkify'); var request = require('request'); var get = thunkify(request.get); co(function *(){ var a = yield get('http://google.com'); var b = yield get('http://yahoo.com'); var c = yield get('http://cloudup.com'); console.log(a[0].statusCode); console.log(b[0].statusCode); console.log(c[0].statusCode); })()
co は引数で渡された generators をラップし、中で generators を実行する。
yield が呼ばれるたびに、返された関数を実行し、
コールバックが呼ばれたら、また元の generators を呼びだす(yield の値は、次に generators を呼び出したときの引数である)。
すごく頭いい、天才か。
ところで、 co で yield するオブジェクトは promise や thunk である必要がある。
サンプルコードでは、 request.get を thunkify というモジュールを使って、 thunk にしている。
では、 thunk とはなにか。
これは、端的にいうと、次のような形をした関数のことである。
var fn = function(args){ return function(callback){ // some process callback(); }; };
Javascript は一般的に callback を最後の引数として書くが、
thunk は callback のみを引数にとる関数を返す。
thunkify は、大体の場合において、callback が最後の引数であることを利用して、
普通の callback つき関数を thunkify する。
まあ、 promise を渡してもいいんだけど、
内部的には thunk に変換してるし、こっちのほうがシンプルで好み。