Promiseを複数の直列処理と並列処理を組み合わせる


そもそもそんな複雑なことしないほうが...
まあそうですね…



今回のタイミングで改めてPromiseやArrayまわりと向き合ったのでメモ


#直列処理
```
const task = (label, timeout) => {
	return () => {
		return new Promise((resolve, reject) => {
			console.log(`${label} start`);
			
			setTimeout(() => {
				console.log(`${label} done`);
				//timeout秒経ったら次へ
				resolve();
			}, timeout);
		});
	}
};

console.log('promise start');
Promise.resolve()
	.then(task('task1', 100))
	.then(task('task2', 200));
```

こんな処理が3回とかだったらまだいいかもしれないが、これが多数となったらこのままthenで続けるような記述をするのはつらすぎる…


そこでArray#reduceを使って記述してみる
[Array.prototype.reduce() - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce)

#Array#reduceを使って直列繋ぎ
```promise-reduce.js
const task = (label, timeout) => {
	return () => {
		return new Promise((resolve, reject) => {
			console.log(`${label} start time: ${timeout}`);
			
			setTimeout(() => {
				console.log(`${label} done`);
				//timeout秒経ったら次へ
				resolve();
			}, timeout);
		});
	}
};

const REPEAT = 10;
[...Array(REPEAT).keys()].reduce((promise, current) => {
	let label = `task${current}`;
  let timeout = Math.floor((Math.random() * 500));
	return promise.then(task(label, timeout));
}, Promise.resolve());

```

## 結果

```$node promise-reduce.js```

```shell
task0 start time: 69
task0 done
task1 start time: 5
task1 done
task2 start time: 191
task2 done
task3 start time: 89
task3 done
task4 start time: 458
task4 done
task5 start time: 112
task5 done
task6 start time: 107
task6 done
task7 start time: 14
task7 done
task8 start time: 284
task8 done
task9 start time: 183
task9 done
```

# 並列×直列処理
この個数が更に増えたら、ちょっとだけ並列にも動かしたい。
でも結果は同時にほしい

```promise-parallel-serial.js
const task = (label, timeout) => {
  return () => {
    return new Promise((resolve, reject) => {
      console.log(`start: ${label}  time: ${timeout}`);
      
      setTimeout(() => {
        console.log(`done:  ${label}  time: ${timeout}`);
        //timeout秒経ったら次へ
        resolve();
      }, timeout);
    });
  }
};

//直列処理は3つ
const REPEAT = 3;
//並列は4つ
const PARALLEL = 4;

const parallels = [...Array(PARALLEL).keys()].map(index => {
  let lastpromise = [...Array(REPEAT).keys()].reduce((promise, current) => {
    let label = `task ${index+1}-${current+1}`;
    let timeout = Math.floor((Math.random() * 500));
    return promise.then(task(label, timeout));
  }, Promise.resolve());

  return lastpromise;
});


Promise.all(parallels).then(() => {
	//並列実行したすべてが完了したとき
  console.log('all done');
});
```

## 結果
```
start: task 1-1  time: 179
start: task 2-1  time: 26
start: task 3-1  time: 199
start: task 4-1  time: 303
done:  task 2-1  time: 26
start: task 2-2  time: 469
done:  task 1-1  time: 179
start: task 1-2  time: 365
done:  task 3-1  time: 199
start: task 3-2  time: 36
done:  task 3-2  time: 36
start: task 3-3  time: 360
done:  task 4-1  time: 303
start: task 4-2  time: 474
done:  task 2-2  time: 469
start: task 2-3  time: 331
done:  task 1-2  time: 365
start: task 1-3  time: 82
done:  task 3-3  time: 360
done:  task 1-3  time: 82
done:  task 4-2  time: 474
start: task 4-3  time: 47
done:  task 4-3  time: 47
done:  task 2-3  time: 331
```

# メモ
- Promise.allはthenをまとめてるだけ。
- async/awaitのほうがわかりやすいだろうな

# 参考
- [Array.prototype.reduce() - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce)
- [promise-book](http://azu.github.io/promises-book/)
- [Array Number Ranges in JavaScript ES6](http://davidarvelo.com/blog/array-number-range-sequences-in-javascript-es6/)