LoginSignup
46
36

More than 5 years have passed since last update.

JavaScriptでループの中で非同期処理を書く

Last updated at Posted at 2018-12-19

for文やmap関数の中でasync/awaitを使うときの書き方をメモします。
各非同期処理を逐次的に実行する方法と、非同期的に実行する方法の2つがあります。

1. 同期的に実行

キャプチャ2.gif

2. 非同期的に実行

キャプチャ2.gif

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番目の方法を使うのが、性能的な面で良いと思います。

以上

46
36
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
46
36