简体   繁体   English

Firebase(角度)承诺在循环中循环

[英]Firebase (Angular) Promises with Loops in Loops

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? 仅在所有promise都解决之后,又如何在循环中等待异步调用的情况下,如何执行函数?

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. 为了提高速度,可以并行执行所有请求,但是只有在解决所有问题后才能调用最终功能bookRental()。

Thanks for your help. 谢谢你的帮助。

EDITED: Another try that failed. 编辑:另一个尝试失败。 The Promise.all('collector') gets fired before all the promises are resolved. Promise.all('collector')在所有诺言都解决之前就被解雇了。 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. .then的代码稍后运行。

Here's what runs immediately: 这是立即运行的内容:

  1. Both nested for-loops run to completion, minus all code inside .then s. 这两个嵌套的for循环都会执行完毕,减去.then内的所有代码。
  2. Promise.all(collector) . Promise.all(collector)

At this point collector is still empty, so Promise.all() completes real fast. 此时collector仍为空,因此Promise.all()快速完成。

Move the collector.push(promise) calls outside of the .then s. collector.push(promise)调用.then之外。

A more functional approach: 一种更实用的方法:

With the above fix, your code should work, but a cleaner approach is to return all promises . 通过上述修复,您的代码应该可以运行,但是更干净的方法是返回所有promise While forEach doesn't allow return values, map does, so this can be re-written as (simplifying): 尽管forEach不允许返回值,但是map允许返回值,因此可以将其重写为(简化):

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'));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM