【问题标题】:AngularJS Sequentially Chain Promises in forEach LoopsAngularJS 在 forEach 循环中顺序链接 Promise
【发布时间】:2017-07-13 06:11:01
【问题描述】:

我一直在进行大量搜索以试图找到解决方案,并相信它最终会兑现承诺,因为我的数据被返回,但最终,我在每次迭代中都需要它。

我有 vm.planWeek.dinner 循环遍历每一行,并将“menuType”和“trackMenuIds”数组附加到它,然后我在 MongoDB 调用中使用它们作为搜索条件。这一切都很好,但关键元素是每个返回的工厂调用,我将返回的项目的 id 添加到“trackMenuIds”数组中。这样做的原因是,它构建了一个我已经返回的项目数组,因此可以在下一次调用中忽略它们,即通过 $nin。

vm.reviewWeek = function () {

    //Array to be updated over each iteration and used in factory call
    var trackMenuIds = [];

    angular.forEach(vm.planWeek.dinner, function (day) {

        //Adds two more items to day(current row) to pass to factory
        day.menuType = 'dinner';
        day.weekIds = trackMenuIds;

        //Factory call - each time this runs, the 'trackMenuIds' array should have 
        //one more item added from the previous run
        menuFactory.matchMenuCriteria(day)
          .then(function (response) {
            var randomItem = response.data[0];
            day.menuItem = {'_id': randomItem._id, 'name': randomItem.name};

            //adds the current id to the array to be used for the next run
            trackMenuIds.push(randomItem._id);
          });
     });
};

当我将 'trackMenuIds' 数组附加到当前行时,它还没有被任何 id 更新。当我对它进行控制台操作时,我可以看到它确实添加了它们,但相信作为承诺的一部分,它没有足够早地将更新后的数组传递到我的工厂调用中。

我尝试了链式承诺和其他方式,但似乎无法让它发挥作用。很可能归结为我对承诺的缺乏经验,所以任何帮助都将不胜感激。

【问题讨论】:

标签: angularjs loops foreach promise angular-promise


【解决方案1】:

对工厂异步 API 的调用是并行进行的。它们需要按顺序链接:

vm.reviewWeek = function () {

    //Array to be updated over each iteration and used in factory call
    var trackMenuIds = [];

    //INITIAL empty promise
    var promise = $q.when();

    angular.forEach(vm.planWeek.dinner, function (day) {

        //Adds two more items to day(current row) to pass to factory
        day.menuType = 'dinner';
        day.weekIds = trackMenuIds;

        //Factory call - each time this runs, the 'trackMenuIds' array should have 
        //one more item added from the previous run

        //CHAIN sequentially
        promise = promise.then(function () {
            //RETURN API promise to chain
            return menuFactory.matchMenuCriteria(day);
        }).then(function (response) {
            var randomItem = response.data[0];
            day.menuItem = {'_id': randomItem._id, 'name': randomItem.name};

            //adds the current id to the array to be used for the next run
            trackMenuIds.push(randomItem._id);
        });
    });

    return promise;
};

上面的例子创建了一个初始的空承诺。然后,foreach 循环在每次迭代时链接到异步 API 的调用。

【讨论】:

    【解决方案2】:

    您可以使用 $q.all 来处理多个异步调用。执行完所有 promise 后,循环遍历原始 Http promise,然后将数据推送到新数组

    vm.reviewWeek = function () {
    
        //Array to be updated over each iteration and used in factory call
        var trackMenuIds = [];
    
        var dinnersPromise = [];
    
        vm.planWeek.dinner.forEach(function (day, ind) {
            //Adds two more items to day(current row) to pass to factory
            day.menuType = 'dinner';
            day.weekIds = trackMenuIds;
            dinnersPromise.push(menuFactory.matchMenuCriteria(day));
        });
    
        $q.all(dinnersPromise).then(function (arr) {
            angular.forEach(arr, function (response) {
                var randomItem = response.data[0];
                day.menuItem = {'_id': randomItem._id, 'name': randomItem.name};
    
                //adds the current id to the array to be used for the next run
                trackMenuIds.push(randomItem._id);
             });
        });
    }
    

    【讨论】:

    • 这不会给我相同的结果吗,因为我需要获取每个 promise 的结果,然后调用下一个,以便将其注入到下一个调用中?
    • @Andrew 结果可能相同,但我使用的方式不同。使用手动循环,你不知道 promise 什么时候执行,假设循环已经在下一次迭代中,你会错过当前的 promise 值。
    猜你喜欢
    • 2014-11-25
    • 2018-05-20
    • 2023-03-22
    • 2016-08-10
    • 2018-02-12
    • 1970-01-01
    • 1970-01-01
    • 2016-06-10
    相关资源
    最近更新 更多