node.jsで使える非同期コントロールフローライブラリ nue その6 - mapの必要性について

id:koichik さんがフロー制御のライブラリ(node-flowless)を作ったそうです。いやー刺激的です。


上記エントリ中の次の文章に反応してみます。

あとは map() なんかの非同期版も重宝ではありますが,そういうのは Async 使えばいいかなー? もしかしたら flowless に入れるかもだけど.


非同期のmapについては、自分も入れるべきかどうか悩んだところです。実際、nueでもちょっと前までは実装していたんですが、通常のforEachがあれば事足りるかなと判断して削りました。nueでは、次のように対応できます。

var flow = require('nue').flow;
var fs = require('fs');

flow(
  function readDir() {
    fs.readdir(__dirname, this.async());
  },
  function readFiles(files) {
    var textFiles = files.filter(function (filename) {
      return /\.txt$/.test(filename);
    });
    // 非同期map相当
    textFiles.forEach(function (filename) {
      fs.readFile(__dirname + "/" + filename, 'utf8', this.async());
    }.bind(this));
  },
  function showAll() {
    var files = Array.prototype.slice.call(arguments);
    files.forEach(function (file) {
      console.log('-----');
      console.log(file);
    });
    this.next();
  }
)();

この例は、(ディレクトリからファイルを読んだ後、txt拡張子を持ったものだけを対象に)ファイル名の配列からファイルのコンテンツに変換しています。forEachの中でthis.async()しているのがポイント。これだけで非同期map相当の処理ができます。


ちょっと注意しなければいけないのは、readFiles関数内のforEach内で読み取った結果はそれぞれ別の引数で次の関数であるshowAllへ渡されるので、showAll関数の中で配列として扱うにはargumentsから変換する必要があります。


ちなみに、これ、Step(https://github.com/creationix/step)のgroupの機能に相当します。サンプルコードもStepのgroupの機能を説明するものをベースにしています。