Promise.all について使い方のメモ
tl;dr;
複数の Promise を使用するときは Promise.all
で解決すると待たなくて済む
事の発端として,複数の http リクエストを送る場合に,前のリクエストが完了するまで処理が進まなかった。 どうやったら前処理を待たずに擬似マルチで処理ができるのかなと思って手を動かして納得できたのでメモ。
検証準備
Promise を複数使用して試したい場合は単純に
new Promise(setTimeout(() => {}), 1000)
とかで十分検証できるとは思うけど,ちょっと味気ないので (勉強も兼ねて) 適当な express サーバーを立てて検証
サーバー側
ルートに対して timeout
のクエリを指定すると,指定秒数待機してからレスポンスを返す簡単なサーバーを立てます。
import express from 'express' const app = express() const port = 3000 app.get('/', (req, res) => { const log = (type: string, time: number) => { console.log(`${Date()}: ${type} - ${time}`) } const timeout: number = parseInt(req.query.timeout as string) log('Request', timeout) setTimeout(() => { res.send(`waited ${timeout}`) log('Response', timeout) }, timeout * 1000 || 0) }) app.listen(port, () => { console.log('start server') })
クライアント側
import axios from 'axios' import assert from 'assert' axios.defaults.baseURL = 'http://localhost:3000' const request = async (time: number) => { console.log(`timeout: ${time}`) assert.strictEqual( (await axios.get('/', { params: { timeout: time } })).data, `waited ${time}` ) }
axios
で GET リクエストを送って,念の為 assert
でチェックします。
単純に await を並べて書くと以下のような結果になります。
// Case A const caseA = async () => { console.time('request') console.log('start') await request(3) await request(5) console.log('done') console.timeEnd('request') }
start timeout: 3 timeout: 5 done request: 8.025s
これでは前のリクエストが完了するまで次の処理に進めないため時間がかかってしまいます。
次は Promise.all
で解決する場合。
// Case B const caseB = async () => { console.time('request') console.log('start') await Promise.all([request(3), request(5)]) console.log('done') console.timeEnd('request') }
start timeout: 3 timeout: 5 done request: 5.016s
以上のように待たずに同時に処理を開始することができました。
今回の検証では全てのリクエストに成功していましたが,一部で失敗してしまうと,reject
を返してしまうそうです (まだ追えてないので後で調べる)。