参考
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の基本
async
キーワードを関数の前につける →async
キーワードをつけた関数はasync function
になるasync function
await
キーワードはasync functionの中でしか使えない- promiseを返す関数になる
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);