3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

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

Last updated at Posted at 2022-08-29

promise-pool

やりたいこと

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

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

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)

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件の処理をする

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をどれくらいの頻度で叩くのか、などを考えて取捨選択すればよろしいかと……。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?