10:22・2021/08/09
カテゴリー
firebase JavaScript非同期処理のPromiseでfor文を複数回す
03:17・2021/10/16 公開
03:17・2021/10/16 更新
という少々厄介な場面に遭遇したので記事を書いておく。
めちゃくちゃハマった経緯
vue.jsでfirestoreからデータを取ってくる際にdata属性への反映が遅く、最初に開いたときに表示されないということで4日間くらいハマりました。
コンポーネントの読み込みを遅延させたり、データを取ってくる場所を変えたり、wachやcomputedで監視してみたり色々しましたが全滅。
その頃にLINEで「データを取ってくるのが間に合ってないのでは」と指摘されて改めてコンソールで取得順を表示すると、たしかに間に合ってない(当たり前体操)。
「promise.allとか使いなよ」とありがたい教示をいただき、私は解決への糸口を掴む───────
参考記事
Promiseとthenのメソッドチェーン(直列・並列・値の受け取り・引数) – Qiita
複数の値の受け取り方法を知らなくてまたハマりかけたので注意。
Promiseの直列処理をループする(完了後に実行したい処理もある) – Qiita
最終的にコードはだいぶ違う形で活用しました。
Promiseってなんぞや編
setTimeoutはダサいぞ。JavaScript Promiseを使って処理を順番に実行しよう – 株式会社LIG
多分これが一番わかりやすい
JavaScriptのPromise – Qiita
promiseはいろんなことに使えるらしい
Promise.all() – MDN
お馴染みのMDN
今回書いたコード
vue.jsの子コンポーネント内に記述しました。
(HOMEに表示する情報の一部です)
import store from "./../../stores";//vuexの読み込み
import { doc, getDoc, collection, getFirestore } from "firebase/firestore";
const db = getFirestore();//firestoreに接続
export default {
data() {
return {
rooms: "",//ここにデータを入れたい
};
},
created() {
let uid = store.getters.user.uid;//ユーザーID
console.log("getrooms");
let rooms_sub = [];//とりあえずこれにデータを入れる
let myPromise1 = Promise.resolve();
let myPromise2 = Promise.resolve();
let getroomID = new Promise((resolve, reject) => {
getDoc(doc(db, "users", uid)).then((docRef) => {
resolve(docRef.data().rooms);//持ってる部屋の一覧を取得
});
});
getroomID.then((roomId) => {
for (var i = 0; i < roomId.length; i++) {
myPromise1 = myPromise1.then(getrooms.bind(this, i, roomId));
}//部屋の数だけ部屋情報を取得
myPromise1.then((value) => {
let i = value[0];
let rooms_sub = value[1];
let members_sub = value[2];
for (var j = 0; j < members_sub.length; j++) {
myPromise2 = myPromise2.then(
getmembers.bind(this, i, j, rooms_sub, members_sub)
);
}//部屋ごとのメンバー情報を取得
myPromise2.then((rooms_sub) => {
store.commit("setRooms", rooms_sub);//vuexにセット
console.log(rooms_sub);
this.rooms = rooms_sub;//dataに代入
});
});
});
function getrooms(i, roomId) {//部屋情報をとってくる
return new Promise(function (resolve, reject) {
let docRef = doc(db, "rooms", roomId[i]);
getDoc(docRef).then((docRef) => {
rooms_sub[i] = {
id: roomId[i],
icon: docRef.data().icon,
name: docRef.data().roomname,
post: docRef.data().post,
member: docRef.data().users.length,
update: docRef.data().update,
members: [],
};
resolve([i, rooms_sub, docRef.data().users]);
console.log(i, roomId);
});
});
}
function getmembers(i, j, rooms_sub, members_sub) {//部屋のメンバー情報をとってくる
return new Promise(function (resolve, reject) {
let docRef2 = doc(db, "users", members_sub[j]);
getDoc(docRef2).then((docRef) => {
rooms_sub[i].members.push({
id: members_sub[j],
name: docRef.data().name,
icon: "",
});
resolve(rooms_sub);
});
});
}
},
};
</script>