Promiseを効率的に処理していく方法

# promise-pool

## やりたいこと

あるAPIを叩いて、データを取ってきたい。20個くらいAPIを叩く先があるけれども、10個ずつ取りにいって、1つの処理が終われば次のAPIを叩きたい。

## 1つずつ取ってくる場合(async await)

```TypeScript
import axios from 'axios';
const first = async () => {
	const start = performance.now();
	const result1 = await axios.get('https://yahoo.co.jp');
	const result2 = await axios.get('https://yahoo.co.jp');
	const result3 = await axios.get('https://yahoo.co.jp');
	const result4 = await axios.get('https://yahoo.co.jp');
	const result5 = await axios.get('https://yahoo.co.jp');
	const result6 = await axios.get('https://yahoo.co.jp');
	const result7 = await axios.get('https://yahoo.co.jp');
	const result8 = await axios.get('https://yahoo.co.jp');
	const result9 = await axios.get('https://yahoo.co.jp');
	const result10 = await axios.get('https://yahoo.co.jp');
	const result11 = await axios.get('https://yahoo.co.jp');
	const result12 = await axios.get('https://yahoo.co.jp');
	const result13 = await axios.get('https://yahoo.co.jp');
	const result14 = await axios.get('https://yahoo.co.jp');
	const result15 = await axios.get('https://yahoo.co.jp');
	const result16 = await axios.get('https://yahoo.co.jp');
	const result17 = await axios.get('https://yahoo.co.jp');
	const result18 = await axios.get('https://yahoo.co.jp');
	const result19 = await axios.get('https://yahoo.co.jp');
	const result20 = await axios.get('https://yahoo.co.jp');
	const end = performance.now();
	console.log({ result: end - start, name: 'first' }); //{ result: 3918.3598749637604, name: 'first' }
};

first();
```

超シンプルなasync awaitで取得してくるバージョンです。重いasync関数をひとつずつ処理していきます。遅いですね。上から1個ずつ取ってこないといけない、みたいな順番が大事なときには良いかもしれません。

## 一気に取りに行く場合(promise all)

```TypeScript
import axios from 'axios';
const second = async () => {
	const start = performance.now();
	const [
		result1,
		result2,
		result3,
		result4,
		result5,
		result6,
		result7,
		result8,
		result9,
		result10,
		result11,
		result12,
		result13,
		result14,
		result15,
		result16,
		result17,
		result18,
		result19,
		result20
	] = await Promise.all([
		 axios.get('https://yahoo.co.jp'),
		 axios.get('https://yahoo.co.jp'),
		 axios.get('https://yahoo.co.jp'),
		 axios.get('https://yahoo.co.jp'),
		 axios.get('https://yahoo.co.jp'),
		 axios.get('https://yahoo.co.jp'),
		 axios.get('https://yahoo.co.jp'),
		 axios.get('https://yahoo.co.jp'),
		 axios.get('https://yahoo.co.jp'),
		 axios.get('https://yahoo.co.jp'),
		 axios.get('https://yahoo.co.jp'),
		 axios.get('https://yahoo.co.jp'),
		 axios.get('https://yahoo.co.jp'),
		 axios.get('https://yahoo.co.jp'),
		 axios.get('https://yahoo.co.jp'),
		 axios.get('https://yahoo.co.jp'),
		 axios.get('https://yahoo.co.jp'),
		 axios.get('https://yahoo.co.jp'),
		 axios.get('https://yahoo.co.jp'),
		 axios.get('https://yahoo.co.jp')
	]);
	const end = performance.now();
	console.log({ result: end - start, name: 'second' }); // { result: 331.03974986076355, name: 'second' }
};

second();
```

promise.allで一気に取りに行く方法です。これが一番早いといえば早いです。20件くらいならいけるかもしれませんが、叩きに行くAPIが貧弱だと100件とかになるとout of memoryが怖くなっていきます。あとは同時接続制限とかに引っかかる可能性もあります。それからエラーのときはどうするか……みたいなことを考えないといけません。allSettledなども検討しないと……。

## Poolで同時10件の処理をする

```TypeScript
import axios from 'axios';
import { PromisePool } from '@supercharge/promise-pool';
const third = async () => {
	const start = performance.now();
	const { results, errors } = await PromisePool.for([
		'https://yahoo.co.jp',
		'https://yahoo.co.jp',
		'https://yahoo.co.jp',
		'https://yahoo.co.jp',
		'https://yahoo.co.jp',
		'https://yahoo.co.jp',
		'https://yahoo.co.jp',
		'https://yahoo.co.jp',
		'https://yahoo.co.jp',
		'https://yahoo.co.jp',
		'https://yahoo.co.jp',
		'https://yahoo.co.jp',
		'https://yahoo.co.jp',
		'https://yahoo.co.jp',
		'https://yahoo.co.jp',
		'https://yahoo.co.jp',
		'https://yahoo.co.jp',
		'https://yahoo.co.jp',
		'https://yahoo.co.jp',
		'https://yahoo.co.jp'
	]).process(async (urls) => {
		return axios.get(urls);
	});
	const end = performance.now();
	console.log({ result: end - start, name: 'third' }); // { result: 550.29279088974, name: 'third' }
};

third();
```

```PromisePool```というライブラリを使うと、同時に10件まで接続して取ってきてくれます（10件の部分は変更できます)。10個まで同時に処理してくれて、1つ処理が終わったら11個目の処理をはじめてくれるという優れたライブラリです。返り値がresultsとerrorsなのもいいね！

最後にもう1回違いをおさらい。

仮に100個のasync関数があったとして……。
async await -> 1から100まで1個ずつ処理
promise.all -> 100個を一気に処理しようとする(たぶんメモリ足らん)
promise.allを10個ずつに分割-> 10個処理→10個が完全に終わる→次の10個の処理
promisePool -> 10個同時処理、1個終わったら11個めが自動で開始される。どんどん処理が進んでいくので早い！

という感じです。

どういうAPIをどれくらいの頻度で叩くのか、などを考えて取捨選択すればよろしいかと……。