在下面的代码中,我将每个项目的密钥和一个电子邮件地址保存在一个表中,并使用所述密钥检索要从原始表中获取的对象。我可以看到,当我在console.log中时,这些项目被放入rawList
数组中,但是函数在它有任何内容之前返回this.cartList
,因此视图没有收到任何内容的数据。如何才能使this.cartList
在返回之前等待rawList
已满?
ionViewWillEnter() {
var user = firebase.auth().currentUser;
this.cartData.getCart().on('value', snapshot => {
let rawList = [];
snapshot.forEach(snap => {
if (user.email == snap.val().email) {
var desiredItem = this.goodsData.findGoodById(snap.val().key);
desiredItem.once("value")
.then(function(snapshot2) {
rawList.push(snapshot2);
});
return false
}
});
console.log(rawList);
this.cartList = rawList;
});
}
我已经尝试将this.cartList = rawList放在许多不同的位置(return false
之前,甚至在.then
语句中,但这并没有解决问题。
答案 0 :(得分:1)
问题是forEach循环(sync)中的Promise(对firebase的异步.once()调用)。 forEach循环不会等待then()语句,所以在下一次迭代中,上一次迭代的数据就丢失了......
let snapshots = [1, 2, 3];
let rawList = [];
snapshots.forEach((snap) => {
console.log(rawList.length)
fbCall = new Promise((resolve, reject) => {
setTimeout(function() {
resolve("Success!");
}, 2500)
});
fbCall.then((result) => {
rawList.push(result);
});
})

你需要forEach将整个Promise推送到rawList然后等待它们解决并做结果。
var snapshots = [1, 2, 3];
var rawList = [];
var counter = 0;
snapshots.forEach((snap) => {
console.log(rawList.length)
var fbCall = new Promise((resolve, reject) => {
setTimeout(function() {
resolve("Success!" + counter++);
}, 1500)
});
rawList.push(fbCall);
})
Promise.all(rawList).then((res) => {
console.log(res[0]);
console.log(res[1]);
console.log(res[2]);
});

问题是,分配this.cartList = Promise.all(rawList)仍然有点尴尬,因为它使它成为一个Promise。那么您可能想重新考虑您的设计并制作类似于getCartList服务的东西? (不知道你的app是什么样的:p)
答案 1 :(得分:1)
由于你正在使用角度,你也应该使用angularfire2
,它会使用Observables
来解决这个问题。您仍然会使用常规SDK进行许多操作,但是为了获取和绑定数据,建议不要在没有angularfire2
的情况下单独使用Firebase,因为这会使这些事情变得不易管理。
这种方法的好处在于您可以利用Observable
上的任何方法,例如filter
,first
,map
等。
安装后,只需执行:
public items$: FirebaseListObservable<any[]>;
this.items$ = this.af.database.list('path/to/data');
在视图中:
{{items$ | async}}
等待数据出现。
答案 2 :(得分:0)
使用AngularFire2和RxJS这将为您节省大量时间,并且您将通过使用RxJS运算符以正确且可维护的方式执行此操作,您可以在此处了解这些运算符{{ 3}}