AngularJS在每个循环中的顺序链承诺

时间:2017-02-22 23:29:20

标签: angularjs loops foreach promise angular-promise

我一直在尝试寻找一个解决方案,并且相信它最终会在我的数据被返回时失去承诺,但最终都是在每个迭代中我需要的地方。

我有循环遍历每一行的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进行更新。当我控制它时,我可以看到它实际上添加它们,但是相信它是一个承诺的一部分,它没有尽早将更新的数组传递到我的工厂调用中每次迭代。

我尝试过连锁承诺和其他方法,但似乎无法让它发挥作用。很可能这归结于我对承诺的缺乏经验,所以任何帮助都会受到高度赞赏。

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分: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的调用。