背景
"awaite Promise.ALL"と"flatMap"メソッドを用いて、引数に設定した全てのPromseオブジェクトにおける非同期処理のresolveを待つ処理を書くことがあったので備忘録としてまとめます。
Promise.ALLとは
Promise.ALLは、引数に設定してるPromiseオブジェクトを返す非同期関数の全ての結果がresolveになった際、結果を返すというものです。
基本構文
Promise.all([promise1, promise2, promise3])
.then((results) => {
console.log(results);
})
.catch((error) => {
console.error(error);
});
今回は上記のpromise1, promise2, promise3をflatMapで作成していきます。
flatMapとは
flatMapとは、mapのような形で、配列をループして新しい配列を組み直すものではあるのですが、「ネストされた値」を一次元(フラット)にして組み直すものとなります
mapとの違い
// map
const arr = [[1, 2], [3, 4], [5]];
const newArr = arr.map((item) => {
return (item = item.map((i) => {
return i * 2;
}));
});
console.log(newArr);
// 出力結果
// [ [ 2, 4 ], [ 6, 8 ], [ 10 ] ]
// flatMap
const testArr = [[1, 2], [3, 4], [5]];
const newTestArr = testArr.flatMap((item) => {
return (item = item.flatMap((i) => {
return i * 2;
}));
});
console.log(newTestArr);
// 出力結果
// [ 2, 4, 6, 8, 10 ]
このように処理後の結果がフラットになります。
想定
下記のように、"連続的な接頭辞_ID_何かしらの情報"をプロパティとし各種値がある形としたものがリクエストデータに格納されているとします。
const obj = {
itemsA_1_name: "Aのアイテム1",
itemsA_1_number: 10,
itemsA_2_name: "Aのアイテム2",
itemsA_2_number: 20,
itemsB_1_name: "Bのアイテム1",
itemsB_1_number: 30,
itemsB_2_name: "Bのアイテム2",
itemsB_2_number: 40,
itemsC_1_name: "Cのアイテム1",
itemsC_1_number: 50,
itemsC_2_name: "Cのアイテム2",
itemsC_2_number: 60,
};
上記からIDのみを抽出し、かつカテゴリー別の配列(今回で言うとA〜C)を作成し、それを元に取得した値を各種任意のテーブルにインサートしていくといった形なのですが、今回は簡易的にコンソールに出力する形とします。
実装
上記のオブジェクトからキーを取り出し、そのキーを引数として値の配列を取得し、その配列に対してmapでPromiseオブジェクトを返す関数を作成します
const obj = {
itemsA_1_name: "Aのアイテム1",
itemsA_1_number: 10,
itemsA_2_name: "Aのアイテム2",
itemsA_2_number: 20,
itemsB_1_name: "Bのアイテム1",
itemsB_1_number: 30,
itemsB_2_name: "Bのアイテム2",
itemsB_2_number: 40,
itemsC_1_name: "Cのアイテム1",
itemsC_1_number: 50,
itemsC_2_name: "Cのアイテム2",
itemsC_2_number: 60,
};
// プレフィックスを元に値を取得する為のカテゴリリスト
const categoryList = ["A", "B", "C"];
const testFn = async () => {
// 他の処理が実行される
console.log("start");
// 全ての非同期処理が終わるまで待つ
await Promise.all(
// カテゴリリストを元にflatMapを使用して一次元配列に変換
categoryList.flatMap((category) => {
// オブジェクトのキーを元にアイテムIDを取得
const itemIds = Object.keys(obj)
.filter((key) => key.startsWith(`items${category}_`) && key.endsWith(`_name`))
.map((key) => key.split("_")[1]);
// アイテムIDを元にオブジェクトのプロパティ名を取得して、それを元にブラケット方式でオブジェクトにアクセスし、アイテムの名前と数を出力
return itemIds.map(async (id) => {
try {
console.log(`アイテムの名前は: ${obj[`items${category}_${id}_name`]}`);
console.log(`アイテムの数は: ${obj[`items${category}_${id}_number`]}`);
} catch (error) {
console.error(error);
}
});
})
);
// 上記が完了次第、他の処理が実行
console.log("end");
};
testFn();
// コンソールの結果
// start
// アイテムの名前は: Aのアイテム1
// アイテムの数は: 10
// アイテムの名前は: Aのアイテム2
// アイテムの数は: 20
// アイテムの名前は: Bのアイテム1
// アイテムの数は: 30
// アイテムの名前は: Bのアイテム2
// アイテムの数は: 40
// アイテムの名前は: Cのアイテム1
// アイテムの数は: 50
// アイテムの名前は: Cのアイテム2
// アイテムの数は: 60
// end
これにて、各種オブジェクトの値を取得することができました。
リクエストボディから特定のプロパティを取得してインサート時のプリペアドステートメントとして活用できます。
まとめ
まとまった接頭辞とIDが付与されたオブジェクトがリクエストに入っている場合、上記の方法で取り出せます。
また、接頭辞をまとめた配列を作成し、それを元に非同期処理を行う場合はPromise.ALLとflatMapの相性が良いと感じましたので、ひとつの手札として覚えておきたいと思いました。