async/awaitメモ

参考

Promise chainで書く方法 developer.mozilla.org

Fetch APIについて developer.mozilla.org

async/awaitについて developer.mozilla.org

サンプル github.com

はじめに

明示的にPromise chainで書く方法よりasync/awaitで(見かけ上)同期的に書く方が読みやすいと思うし、そもそもasync/awaitで書く方がスタンダードだと思うので使用方法と典型的なパターンをメモする。

async/awaitの基本

  1. async キーワードを関数の前につける → async キーワードをつけた関数はasync function になる

    async function

    • await キーワードはasync functionの中でしか使えない
    • promiseを返す関数になる

    async function - JavaScript | MDN

  2. async function 内でawait キーワードを置く

    • await キーワードと組み合わせないとasync function の利点が活きてこない
    • await の機能は以下だけ。

      await can be put in front of any async promise-based function to pause your code on that line until the promise fulfills, then return the resulting value.

    • await キーワードは以下の条件を満たす関数の前に置くことができる。つまり少なくともasync function の前には置くことができる

      • 非同期関数
      • promiseを返す

Promise chainからasync/awaitへの書き換え

基本的には変換可能?thenをすべてなくすことができる。もちろんPromise chainとasync/awaitのハイブリッドでもいい

典型パターン

fetchでデータを取得するasync function

https://github.com/node-fetch/node-fetch

node-fetchを使った例

注意:node-fetch@2.XはCommonJSと互換がある, 3.XはESMモジュール。Lambdaで使う際に引っかかった。node環境で3.Xを使うならpackage.json"type": "module" の追記が必要。

import fetch from 'node-fetch';

// 1.async functionの定義
async function myAsyncFunc() {

    //fetchは非同期関数かつpromiseを返すのでawaitキーワードを置ける
    const response = await fetch('https://api.github.com/users/github'); // Block this line

    if(!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
    }

    //ここでもawait必要
    const data = await response.json();
    //処理を実装
    console.log(data);
    //取得したデータを返してもいい
    return data
}

// 2. 1.で定義したasync funcitonを使う
// 戻り値を使う際は、ここでもawaitが必要。myAsyncFuncはasync functionなのでawaitを置ける
// awaitを置かない場合はPromiseが返る
const data = await myAsyncFunc()
.catch(e => {
    console.log('There has been a problem with your fetch operation: ' + e.message);
})

console.log(`Name: ${data.name}`);

並列実行パターン(Promise.all)

よーいドンで並列に非同期関数を実行する場合は、気をつけないと性能劣化する。加えて、Promise.allを使わないとハンドリングできないエラーが発生するそう。

まだこのパターンが必要になったことがないので、必要になった際に追記する。(実際に使うとしたら以下のような例だと思う。)

import fetch from 'node-fetch';

// 1.async functionの定義
async function myAsyncFunc() {

    //fetchは非同期関数かつpromiseを返すのでawaitキーワードを置ける
    const response = await fetch('https://api.github.com/users/github'); // Block this line

    if(!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
    }

    //ここでもawait必要
    const data = await response.json();
    //処理を実装
    //console.log(data);
    //取得したデータを返してもいい
    return data
}

const promiseArr = [];
//10個の並列呼び出し
for(let i = 0; i < 10; i++) {
    //ここがポイント。あえてawaitを置かずにPromiseを取得する。
    const p = myAsyncFunc();
    promiseArr.push(p);
}

//Promiseがすべて解決するのをここで待つ
const results = await Promise.all(promiseArr);
console.log(`Length of results: ${results.length}`);
console.log(results);