async, awaitを利用して非同期処理を制御

ECMAScript2017で導入された、async/awaitを利用すると、非同期処理を見通しよく書くことができます。ここでは、「async/awaitの使い方」「Promiseとの違い」を解説します。

サンプルソースで基本的な使い方を確認

まず、以下サンプルソースで動作確認してみます。

const func = () => {
  // 非同期処理
  asyncFunc()

  // asyncFuncの結果を待たずに実行
  console.log(3)
}

const asyncFunc = async () => {
  const sleep = () => {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve(1)
      }, 2000)
    })
  }

  const x = await sleep()

  // sleepの結果を待ってから実行
  console.log(x)
  console.log(2)
}

func()
3
1
2

async

関数の前に、async を付けると async関数 になります。 (今回だとasyncFunc関数)
asyncFunc関数の結果を待たずに、3が出力されています。

await

async関数内部では、sleep関数の前に await が付けられています。
sleep関数の結果を待ってから、1, 2と出力されています。
つまり、 await を付けると、非同期処理内部で処理が一時停止されます。

await は、async関数の中でのみ使えます。
await を付けた関数が、Promiseの結果を返すまで、一時停止します。

IE11では対応していない
ブラウザごとの対応状況を以下ページで確認できます
https://caniuse.com/#feat=async-functions

利用する場合、Babel等でトランスパイルの対応が必要か確認しておく必要があります。

エラー処理

async/awaitPromise より、エラー処理の記述がわかりやすいと言われています。
どのようにわかりやすいのか確認します。

const sleep = () => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(2)
    }, 2000)
  })
}

const syncFunc1 = () => {
  console.log(1)
}

const syncFunc2 = () => {
  console.log(3)
}

非同期処理のsleepと同期処理のsyncFunc1, syncFunc2を記述してます。

  • Promiseで利用した場合
  • async/awaitで利用した場合

を比較します。

Promiseの場合

const promiseFunc = () => {
  try {
    syncFunc1()
 
    sleep().then(data => {
      console.log(data)
      syncFunc2()
    }).catch((err) => {
      console.log(err)
    })
  } catch (err) {
    console.log(err)
  }
}

promiseFunc()

以下目的で、 catch が2回書かれています。

  • sleep(非同期処理) の例外をキャッチするため
  • syncFunc1(同期処理) の例外をキャッチするため

async/awaitの場合

const asyncFunc = async () => {
  try {
    syncFunc1()
    console.log(await sleep())
    syncFunc2()
  } catch (err) {
    console.log(err)
  }
}

asyncFunc()

こちらは、 catch が1回だけ書かれています。
1回のcatchで 同期処理(syncFunc1, syncFunc2)非同期処理(sleep) の例外をキャッチすることができます。

非同期処理の同時実行

awaitPromise.all を利用することで、非同期処理を同時実行することができます。

const sleep = data => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(data)
    }, 2000)
  })
}

const asyncFunc = async () => {
  const [x, y] = await Promise.all([
    sleep(3), sleep(10)
  ])
  console.log(x)
  console.log(y)
}

asyncFunc()
3
10
わくわくBank.
フリーランスのエンジニアとして活動してます。ここでは、ソフトウェア開発で必要とされる技術、用語、概念を整理しています。