Firebase(角度)承诺在循环中循环 [英] Firebase (Angular) Promises with Loops in Loops
问题描述
只有在所有promise都解决了之后,才能在循环内等待异步调用的情况下,如何执行功能?
How do you execute a function only after all the promises are resolved where you have to wait for async calls in loops within loops?
代码已简化到最小
$scope.book = function(input) {
//Get the cart items from DB
ref.child('/cart/' + userId).once('value').then(function(cartSnap) {
//Loop through the cart items
cartSnap.forEach(function(cartItemSnap) {
var itemId = cartItemSnap.key();
//Get the inventory items from DB that are in the cart
ref.child('/inventory/' + itemId).once('value').then(function(inventoryItem) {
//Loop through booking IDs of inventoryItem
inventoryItem.child('rentals').forEach(function(rentalSnap) {
var rentalId = rentalSnap.key();
//Get bookings from rental/active
ref.child('/rental/'+ rentalId).once('value').then(function(activeRentals) {
checkIfBookingIsAllowed();
});
});
});
});
//Once everything was checked
bookRental();
});
};
为了提高速度,所有请求都可以并行进行,但最终功能bookRental()仅在所有问题解决后才能调用.
To improve speed all the requests can be made in parallel but the final function bookRental() can only be called when everything is resolved.
感谢您的帮助.
另一个尝试失败了.Promise.all('collector')在所有诺言被兑现之前就被解雇了.因此,在控制台中的所有检查"之前都会显示完成".
EDITED: Another try that failed. The Promise.all('collector') gets fired before all the promises are resolved. So 'done' shows up before all the 'checks' in the console.
$scope.book = function(input) {
//Get the cart items from DB
ref.child('/cart/' + userId).once('value').then(function(cartSnap) {
//Promise collector
var collector = [];
//Loop through the cart items
cartSnap.forEach(function(cartItemSnap) {
var itemId = cartItemSnap.key();
//Get the inventory items from DB that are in the cart
var promise1 = ref.child('/inventory/' + itemId).once('value').then(function(inventoryItem) {
//Loop through booking IDs of inventoryItem
inventoryItem.child('rentals').forEach(function(rentalSnap) {
var rentalId = rentalSnap.key();
//Get bookings from rental/active
var promise2 = ref.child('/rental/'+ rentalId).once('value').then(function(activeRentals) {
console.log('check');
collector.push(promise2);
});
});
collector.push(promise1);
});
});
//Once everything was checked
Promise.all(collector).then(function() {
console.log('Done');
});
});
};
推荐答案
您收拾承诺的时间太晚了.立即收集它们,现在.中的代码.然后
s稍后运行.
You're collecting the promises too late. Collect them now, not later. Code inside .then
s runs later.
这是立即运行的内容:
- 两个嵌套的for循环都运行完毕,减去
.then
s中的所有代码. -
Promise.all(collector)
.
- Both nested for-loops run to completion, minus all code inside
.then
s. Promise.all(collector)
.
此时, collector
仍然为空,因此 Promise.all()
可以快速完成.
At this point collector
is still empty, so Promise.all()
completes real fast.
将 collector.push(promise)
调用移到之外.然后
s.
使用上述修复程序,您的代码应该可以工作,但是更干净的方法是退还所有诺言.尽管 forEach
不允许返回值,但 map
允许返回值,所以可以将其重写为(简化):
With the above fix, your code should work, but a cleaner approach is to return all promises. While forEach
doesn't allow return values, map
does, so this can be re-written as (simplifying):
Promise.all(cartSnap.map(snap => ref.child(itemUrl).once('value').then(item =>
Promise.all(item.child('rentals').map(snap => ref.child(url).once('value'))))))
.then(allActiveRentals => console.log('Done'));
这篇关于Firebase(角度)承诺在循环中循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!