JavaScript

async-await 構文

async-awaitは、「いつ完了するか分からない処理」だけど「順番に実行したい」な事をするために使います。「コールバック地獄」と呼ばれていたような読みづらいコードをシンプルに書けます。

構文

functionの前、アロー関数なら(の前にasyncと書きます。

async function foo() {
  /* ... */
}
const bar = async () => {
  /* ... */
};

そして、中でPromiseを返す関数の実行前にawaitと書けば、処理が終わるまでその場で待ってくれます。

/**
 * 1病待つ
 * (`async`と書くと`Promise`だなとわかるのでオススメしたい)
 */
const delay = async () => new Promise(r => setTimeout(r, 1000));

(async () => {
  console.log('すぐ表示');
  await delay();
  console.log('1秒後表示');
  await delay();
  console.log('さらに1秒後');
})();

エラー処理

await文の例外はtry-catchで扱えるようになります。

class OversleepError extends Error {
  constructor() {
    super('寝坊した');
    Error.captureStackTrace(this, OversleepError);
  }
}

/**
 * 寝る
 */
const sleep = async () => {
  /* ... */
  throw new OversleepError();
  /* ... */
};

(async () => {
  try {
    await sleep();
  } catch (err) {
    console.log(err instanceof OversleepError); // true
  }
})();

また、扱うのはPromiseなのでcatchで一旦受け取ってできるだけ処理するといったことも。

/* 上の関数定義そのまま */

const eatBreakfast = async () => {
  /* 食べる */
};

(async () => {
  const task = {
    breakfast: true
  };

  await sleep().catch(err => {
    if (err instanceof OversleepError) {
      task.breakfast = false;
      return;
    }

    // error が OversleepError じゃない場合、ここでは扱えないので
    // 再度 `catch` か `try-catch` で扱える形にして
    // 親スコープなどで処理する
    throw err;
  });

  if (task.breakfast) {
    await eatBreakfast();
  }
})().catch(err => {
  /* OversleepError 以外のエラーを扱う */
});