• ..

React

    非同期 async-await

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

    構文

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

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

    そして、中でPromiseを返す関数の実行前にawaitと書けば、処理が終わるまでその場で待ってくれます。これはPromise#thenを使う方法と比べて構文を反対に書いたような形になります。つまり「関数→then→変数」から「変数→await→関数」といった具合です。

    // Promise#then
    asyncFn1().then(data => {/*...*/});
    asyncFn2().then(() => {/*...*/});
    
    // await
    const data = await asyncFn1();
    await asyncFn2();

    以下は1毎にコンソールにテキストを出力する例です。

    /**
     * 1秒待つ
     * (
     *    `async`と書くと`Promise`だなとわかるのでオススメしたいです
     *    TypeScript 除く
     *  )
     */
    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でキャッチすることができます。(エラーでやっているけど単に勉強の為でPromise#rejectでも良い)

    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;
        }
      });
    
      // 遅刻してない場合、
      // 朝食を食べる
      if (task.breakfast) {
        await eatBreakfast();
      }
    })();