问题
I have been doing lots of searching trying to find a solution, and believe it ultimately comes down the the promise as my data is returned but all at the end, where as I need it through each iteration.
I have the vm.planWeek.dinner that I loop through each row, and append 'menuType' and the 'trackMenuIds' array to it, which I then use in my MongoDB call for search criteria. This all works fine, but the key element, is with each factory call returned, I add the returned item's id to the 'trackMenuIds' array. The reason for this is, it builds an array of items I already have returned, so they can ignored in the next call, ie via $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);
});
});
};
When I append the 'trackMenuIds' array to the current row, it hasn't been updated with any id's. When I console it, I can see it does infact add them, but believe as its part of a promise, it is not doing it early enough to pass the updated array into my factory call over each iteration.
I have tried chain promises and other means but just can't seem to get it to work. Quite possibly it comes down to my inexperience of promises, so any help would be greatly appreciated.
回答1:
The calls to the factory asynchronous API are being made in parallel. They need to chained sequentially:
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;
};
The above example creates an initial empty promise. The foreach loop then chains a call to the asynchronous API on each iteration.
回答2:
You can use $q.all to handle multiple asynchronous call. Once all promise done execute, loop through raw Http promise and then push the data to the new array
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);
});
});
}
来源:https://stackoverflow.com/questions/42404285/angularjs-sequentially-chain-promises-in-foreach-loops