複数ファイルを同時ダウンロードして順番に書き出す
@yssk22 さんの node.js ハンズオン資料に「複数ファイルを同時ダウンロードして順番に書き出す」というサンプルがあります。
http://dl.dropbox.com/u/219436/node.js/handson/build/html/intro/async_io.html#id8
今回は、このサンプルを拝借して、同等の処理をnueを使って書いたらどんなコードになるか試してみました。
変更点は次の通り
- モジュールにnueを追加し、flowとas関数をvarで定義。
- download関数のシグニチャを修正。indexの代わりにcallbackをとるように変更。
- download関数の中でnotifyDone関数を呼び出している箇所を、callbackを呼び出すように変更。
- allDone関数で使っているdownloads変数をパラメータで渡すように変更。
- notifyDone関数を削除。
- mainFlow関数を追加し、download関数とallDown関数の呼び出しをflowの中で実施。
こんな感じになりました。
// モジュール読み込み var util = require('util'); var url = require('url'); var http = require('http'); var flow = require('nue').flow; var as = require('nue').as; function download(urlStr, callback){ var u = url.parse(urlStr); var client = http.createClient(u.port || 80, u.hostname); var request = client.request('GET', u.pathname, { host: u.hostname }); request.end(); // リクエストの送信終了 // response イベントの非同期処理 request.on('response', function(response){ // データ取得イベントの非同期処理 var buff = ''; response.setEncoding('utf8'); response.on('data', function(chunk){ // chunk は受信したデータ (デフォルトでUTF8 エンコード) buff += chunk; }); // レスポンス終了イベントの非同期処理 response.on('end', function(){ callback(null, response, buff); }); }); } // 全部の処理が終わったら実行される function allDone(downloads){ for(var i in downloads){ var r = downloads[i]; console.log("---- [" + i + "] "); console.log(r.response.statusCode); for(var j in r.response.headers){ console.log(j + ": " + r.response.headers[j]); } console.log(''); util.print(r.body); console.log(''); } } // nueを使ったフロー制御 var mainFlow = flow('main')( function startDownload(urls) { this.asyncEach(urls, function (url, group) { download(url, group.async({response: as(1), body: as(2)})); }); }, allDone, function end() { if (this.err) throw this.err; } ); var urls = process.argv.slice(2); mainFlow(urls);
こんな感じで実行できます。
node donwload.js http://www.google.co.jp/ http://nodejs.org/
書いてみるまで気づかなかったのですが、主要な処理を行うdownloadとallDoneの両関数をnueに依存させる必要がなかったというのがナイスなポイントです。
非同期な処理を行う関数(download)は、やはりcallbackを受け取るようすることでnueからも呼び出しやすくなりますね。
主要な関数はnueに依存させずに書く、しかもflowの外に書く。非同期処理はcallbackを受け取るようにする。関数は粗結合にする。間をnueでつなぐ。というのが理想かな?