この記事は、どっかからAPIをとってきたデータを、firebaseのデータ群と比較参照する場合、
非同期処理とfor文をどうやって組み合わせれば良いかというところにいつも引っかかっていてしまっていたので、その備忘録です。
環境
- Node.js
- Cloud firestore
どんな問題なのか
firestore にあるcollection からデータを全てとってくる場合、下記の例のように、forEach
を使ってとってくるのが普通です。
var query = db.collection('contents').get();
query
.then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
... // childsnapshot の処理
});
});
しかし、このforEach
文の中、つまり、childsnapshot
の処理の中に、時間がかかる関数を呼び出していて非同期処理をする必要があるとなった場合、
forEach
は非同期処理に対応していないため、一筋縄でいかないのが問題でした。
具体的に、下記のような重い処理をchildSnapshot
の処理内で行うと、
var query = db.collection('contents').get();
query
.then(function(snapshot) {
snapshot.forEach(async function(childSnapshot) {
console.log('before_func');
await heavyfunc(childSnapshot); //重い処理
console.log('after_func');
});
});
const heavyfunc = function(data){
... // API をとってくるなどの重い処理
console.log('inside_func');
}
// snapshot が2つのdataを持っている場合
before_func
after_func
before_func
after_func
inside_func
inside_func
このような結果が得られ、heavyfunc
の処理がforEach
の処理に追いついていない状態になります。
どうやったか
var query = db.collection('contents').get();
query
.then(async function(snapshot) {
for await(let childSnapshot of snpashot.docs){
console.log('before_func');
await heavyfunc(childSnapshot); //重い処理
console.log('after_func');
}
});
const heavyfunc = function(data){
... // API をとってくるなどの重い処理
console.log('inside_func');
}
forEach
ではなく、for ~ of
を使ってループ内での非同期処理を実現しました。
具体的に
-
for ~ of
を使う際、そのループにもawait
を付けたす必要がありました。 -
snapshot
のデータを一つずつ取ってくる時に、snapshot.docs
のようにdocs
を呼び出さないと、データを取得することが出来ませんでした。