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