2017-02-22 87 views
1

Я много искал, пытаясь найти решение, и считаю, что это в конечном итоге сводится к обещанию, поскольку мои данные возвращаются, но все в конце, где, когда мне это нужно, каждый итерация.AngularJS Sequential Chain Promises in forEach Loops

У меня есть vm.planWeek.dinner, что я прокручиваю каждую строку и добавляю к нему 'menuType' и массив 'trackMenuIds', который затем я использую в своем вызове MongoDB для поиска. Все это работает отлично, но ключевым элементом является возврат каждого заводского вызова, я добавляю идентификатор возвращенного элемента в массив '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» в текущей строке, он не был обновлен с любыми идентификаторами. Когда я утешаю его, я вижу, что он действительно добавляет их, но, полагая, что это часть обещания, он не делает этого достаточно рано, чтобы передать обновленный массив в мой заводский вызов на каждой итерации.

Я пробовал цепи обещаний и других средств, но просто не могу заставить его работать. Вполне возможно, что это сводится к моей неопытности обещаний, поэтому любая помощь будет очень признательна.

+0

Возможный дубликат [Закрытие внутренних циклов JavaScript - простой практический пример] (http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – Phil

ответ

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 на каждой итерации.

+0

спасибо, это сработало отлично. – Andrew

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

Это не даст мне тот же результат, поскольку мне нужно получить результат каждого обещания bedore, который называется следующим, чтобы ввести его в следующий звонок? – Andrew

+0

@ И, наконец, результат может быть таким же, но способ использования ими отличается. С ручным циклом вы не знаете, когда обещание будет выполнено, и пусть говорят, что цикл уже находится на следующей итерации, вы пропускаете текущее значение обещания. – digit