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?
The code is simplified to the minimum
$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();
});
};
To improve speed all the requests can be made in parallel but the final function bookRental() can only be called when everything is resolved.
Thanks for your help.
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');
});
});
};
You're collecting the promises too late. Collect them now , not later. Code inside .then
s runs later.
Here's what runs immediately:
.then
s. Promise.all(collector)
. At this point collector
is still empty, so Promise.all()
completes real fast.
Move the collector.push(promise)
calls outside of the .then
s.
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'));
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.