for文やmap関数の中でasync/awaitを使うときの書き方をメモします。
各非同期処理を逐次的に実行する方法と、非同期的に実行する方法の2つがあります。
1. 同期的に実行
2. 非同期的に実行
awaitを使いたい非同期処理は以下
sleep.js
// 引数に指定した秒数だけ待つsleep関数
// Promiseを返す
function sleep(second) {
return new Promise(resolve => {
setTimeout(() => {
resolve()
}, second * 1000)
})
}
1. 同期的に実行する方法
for文の中でawait
を使って書くと、forループの中身を順番に処理してくれるので、同期的に実行してくれます。ここではカウンタを使ったfor文を書いていますが、for .. of
文を使っても同じ挙動になります。
syncLoop.js
async function syncLoop() {
// 1~5までのランダムな整数の配列を生成
const ran_arr = Array(5).fill(0).map(() => Math.floor(Math.random() * 5 + 1))
// for文を使ってループ処理する
for (let i = 0; i < ran_arr.length; i++) {
await sleep(ran_arr[i]) // n秒待つ
console.log(i+1 + "番目の処理が完了!!" + "待ち時間は" + ran_arr[i] + "秒!!")
}
console.log("終了!!")
}
// 実行
// awaitはトップレベルで使うことができない(ES2017時点)ので
// asyncをつけた即時関数を作って呼び出している
(async ()=>{
console.log("同期的に呼び出す")
await syncLoop()
}).call()
2. 非同期的に実行する方法
mapを使います。mapの引数に指定する関数をasync
関数にしておくことで、mapの中で呼ばれる処理を非同期に実行しつつ、mapの返り値であるPromise<void>[]
をPromise.all()
関数で待ち受けることで、 すべての処理の完了を待つことができます。
asyncLoop.js
async function asyncLoop() {
// 1~5までのランダムな整数の配列を生成
const ran_arr = Array(5).fill(0).map(() => Math.floor(Math.random() * 5 + 1))
// mapを使ってループ処理する
await Promise.all(ran_arr.map(async (n, i) => {
await sleep(n) // n秒待つ
console.log(i+1 + "番目の処理が完了!!" + "待ち時間は" + n + "秒!!")
return
}))
console.log("終了!!")
}
// 実行
// awaitはトップレベルで使うことができない(ES2017時点)ので
// asyncをつけた即時関数を作って呼び出している
(async ()=>{
console.log("非同期的に呼び出す")
await asyncLoop()
}).call()
1番目の方法は次のループの処理をブロッキングしてしまうので、基本的には2番目の方法を使っておいて、どうしても非同期処理の実行順序を制御したいときのみ1番目の方法を使うのが、性能的な面で良いと思います。
以上