For

2022.12.26

array.map()内で実行する非同期関数をasync/awaitで同期的に処理する方法

概要

今回は連続して実行したい非同期処理のサンプルとして 郵便番号から住所を取得するAPI を利用します。
このAPIにリクエストしたい郵便番号を配列で保持していて、その配列内の各要素を使って順番にリクエストし、すべてのレスポンスが返ってきてからコンソールに結果を表示します。

array.map()内の関数でasync/awaitするだけでは期待通りにならない

当然といえば当然なのですが、以下のように書くと期待通りになりません。

TypeScript_____NG_____const postalCodes = ['7830060', '1030004'];

const addresses = postalCodes.map(async (postalCode) => {
  const response = await fetch(`https://zipcloud.ibsnet.co.jp/api/search?zipcode=${postalCode}`);
  const { results } = await response.json();
  return results[0].address1 + results[0].address2 + results[0].address3;
})

console.log(addresses);

// 結果(Promiseが解決できていない)
// [[object Promise] { ... }, [object Promise] { ... }]


非同期処理の配列をPromise.all()に渡しPromise.all()をawaitする

続いて、期待通りになるサンプルです。

TypeScript_____OK_____const getAddresses = async (postalCodes: string[]) => await Promise.all(postalCodes.map(async (postalCode): Promise<string> => {
  const response = await fetch(`https://zipcloud.ibsnet.co.jp/api/search?zipcode=${postalCode}`);
  const { results } = await response.json();
  return results[0].address1 + results[0].address2 + results[0].address3;
}));

(async () => {
	console.log(await getAddresses(['7830060', '1030004']));
})();

// 結果
// ["高知県南国市蛍が丘", "東京都中央区東日本橋"]


こうすることで、mapからのPromiseオブジェクトの配列ひとつひとつをawaitして処理を進められます。
Nuxtのサイトマップ生成などでいい感じに利用できます。