Promiseの関数イディオム

環境：`v0.10.41`

## 非同期タスクを動的に生成し、Waterfall実行する
Promiseを使ってWaterfallを実現したい時、下記のようにメソッドチェーンで記述することが出来る。

```js
taskA.then(taskB)
	.then(function(){
		console.log('DONE');
	});
```

しかし、「特定URLのパラメータを20ずつインクリメントしながら5回順次叩く」というような多数の非同期タスクを順次実行したい場合、実行したいタスク個分の`then()`を書かなくてはならず、下記のように記述がとても煩雑になってしまう。（`fetch()`は1秒後に`resolve()`をコールする。）

```js
var Promise = require('promise');

function fetch(param) {
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log(param);
            resolve();
        }, 1000);
    });
}

(function main() {
    var tasks = [0,1,2,3,4].map(function(index) {
        return function() {
            return fetch(index);
        };
    });

    tasks[0]()
        .then(tasks[1])
        .then(tasks[2])
        .then(tasks[3])
        .then(tasks[4])
        .then(function() {
            console.log('DONE!');
        });
})();
```

そこでPromiseをシンプルにWaterfallで実行する関数イディオム(`promiseWaterfall()`)が下のコード。
`promiseWaterfall()`はPromiseオブジェクトを返す関数の配列を引数に取り、メソッドチェーンを生成し、最後に実行される関数のPromiseオブジェクトを返す。

```js
var Promise = require('promise');

function promiseWaterfall(tasks) {
    var finalTaskPromise = tasks.reduce(function(prevTaskPromise, task) {
        return prevTaskPromise.then(task);
    }, Promise.resolve());                                                                                                                                                        

    return finalTaskPromise;
}

function fetch(param) {
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log(param);
            resolve();
        }, 1000);
    });
}

(function main() {
    var tasks = [0,1,2,3,4].map(function(index) {
        return function() {
            return fetch(index);
        };
    });

    promiseWaterfall(tasks).then(function() {
        console.log('DONE!');
    });
})();

```

これくらいの内容だと記述量が逆に増えてしまうが、処理が多数ある場合にとても効果を発揮する。

と思ったらv0.11以降（v0.11は`--harmony`オプションが必要）は`yield`と [co](https://github.com/tj/co) というモジュールの組み合わせでより直感的に書けるらしい。
[Node.js - 最近のjs非同期処理 PromiseとGeneratorの共存 - Qiita](http://qiita.com/kidach1/items/d997df84a0ede39d76ad)
v0.10の世界で生きていた。。。辛い。

## 非同期処理を不定回数実行する
次は一定回数の実行ではなく、不定回数の非同期処理を繰り返す処理をPromiseで書く。
下の`fetchItems()`は引数で与えられた個数分itemを取得して返す。
`fetch()`は要素数3の配列を返すように上述のコードを書き換えたもの。

```js
var Promise = require('promise');

function fetch(param) {
    return new Promise(function(resolve) {
        setTimeout(function() {
            var items = [param, param, param];
            console.log('fetch() returns:', items);
            resolve(items);
        }, 1000);
    });
}

function fetchItems(count) {
    var items = [];

    return new Promise(function(resolve) {
        var recursiveFetch = function(index) {
            fetch(index).then(function (result) {
                items = items.concat(result);

                if (items.length > count) {
                    resolve(items.slice(0, count));
                } else {
                    recursiveFetch(++index);
                }
            });
        };

        recursiveFetch(0);
    });
}

(function main() {
    fetchItems(10).then(function(result) {
        console.log('fetchItems() returns:', result);
    });
})(); 
```

実行結果は下のようにログが1秒おきに1行ずつ表示される。

```shell
$ node index.js 
fetch() returns: [ 0, 0, 0 ]
fetch() returns: [ 1, 1, 1 ]
fetch() returns: [ 2, 2, 2 ]
fetch() returns: [ 3, 3, 3 ]
fetchItems() returns: [ 0, 0, 0, 1, 1, 1, 2, 2, 2, 3 ]
```

これもたぶん`yeild`と`co`を使えば...