業務の中で触れたので、知識の定着&備忘のために記録します。
Promise.allを使って並列処理する
まずは、前提になる並列処理についてです。
itemA, itemBに代入したいデータを返すfuncA, funcBという2つの非同期関数があるとして、並列処理をしようと思うと、こうなります。
// funcAが終わってからfuncBを処理するので処理に時間がかかる
var itemA = await funcA();
var itemB = await funcB();
// 並列処理をするパターン
var promises = [
funcA(),
funcB()
];
var [itemA, itemB] = await Promise.all(promises);
ネストさせる
ここから、自分が直近勉強した並列処理の応用です。
以下のオブジェクトについて、firestoreからデータをフェッチして、新しい配列をつくる処理を考えます。関数の中身は適当です。
下のitemsという配列に入ってる動画とそのサムネイルのファイルを、
それぞれfirebase storageにアップロードして、帰ってきたurlをオブジェクトに紐付ける処理を考えます。
// 対象のオブジェクト
var items = [
{thumbnail: file, video: file},
{thumbnail: file, video: file},
{thumbnail: file, video: file},
];
// idからデータを取得する関数
var uploadFile = async(file) => {
var ref = firebase.storage().ref();
var snapshot = await ref.child('test').put(file);
// urlを返す
return await snapshot.ref.getDownloadURL();
};
やりかたはこうなります。
//配列
var promises = items.map(async(item) => {
var upload_promises = [
uploadFile(item.thumbnail),
uploadFile(item.video)
];
var [thumbnail_url, video_url] = await Promise.all(upload_promises);
// オブジェクトとして返す
return {thumbnail_url, video_url};
});
//[{thumbnail_url: 'https://~~', video_url: 'https://~~'},{...},...]が返ってくる
var urls = await Promise.all(promises);
この記事にあるように、forEachでasync/awaitを使うと順番が担保できなくなる、というのは知っていたので、なんとなくmapでasync/awaitを使っていいのかな、という疑問というか不安みたいなものがあったのですが、この書き方だと順番も担保されたまま並列処理ができます。