JavaScriptで非同期処理を書く方法として、前回Promiseを紹介しました。 Promiseとあわせてもちいることで、非同期処理をよりスマートに書けるのがasync/awaitです。 今回はこれについてまとめてみました。

Promiseの問題点

Promiseは非同期処理を渡してオブジェクトを生成し、これをthen/catchで実行します。

すべての非同期処理を統一的なインタフェースで操作できるというメリットがある一方で、

  • 非同期処理を逐次的に実行しようとすると、そのたびにthenが必要になる
  • 非同期処理の結果が次のthenにしか渡らない

という問題点があります。

たとえば、APIからリソースを取得する処理を考えてみます。

function fetchItems(url) {
  return fetch(url)
    .then((res) => {
      if (res.status != 200) {
        throw new Error('リソースを読み込めませんでした');
      }
      return res;
    })
    .then((res) => {
      return res.json()
        .catch((error) => {
          throw new Error('JSONの形式が正しくありません');
        });
    });
}

上記のコードは、ステータスコードのチェックとJSON化の2つの処理しか行なっていませんが、すでにちょっと見づらいです。 処理が増えるとthenが増え、複雑な処理だとネストも深くなってしまいます。

また、JSON化の処理以降ではレスポンス情報が失われる、という問題もあります。

async/await

ES7のasync/awaitを用いると、非同期処理であるPromiseの結果を同期的であるかのように受け取ることができます。

前述の例は、次のように書き直せます。

async function fetchItems(url) {
  const res = await fetch(url);

  if (res.status != 200) {
    throw new Error('リソースを読み込めませんでした');
  }

  return await res.json()
    .catch(() => {
      throw new Error('JSONの形式が正しくありません');
    });
}

前述の問題点が解消された上、thenという余計なコンテキストスイッチがないため、コードも理解しやすくなりました。

参考記事

おわりに

非同期処理をなんでもasync/awaitで書けばよいという訳ではありませんが、ケースによってはより分かりやすいコードになると思います。