Как использовать promise в цикле forEach массива для заполнения объекта

я запускаю цикл forEach на массиве и делаю два вызова, которые возвращают обещания, и я хочу заполнить объект say this.options, а затем сделайте с ним другие вещи. Прямо сейчас я сталкиваюсь с проблемой асинхронности, если я использую следующий пример кода, и я сначала попадаю в функцию then.

$.when.apply($, someArray.map(function(item) {
    return $.ajax({...}).then(function(data){...});
})).then(function() {
    // all ajax calls done now
});

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

array.forEach(function(element) {
    return developer.getResources(element)
        .then((data) = > {
            name = data.items[0];
            return developer.getResourceContent(element, file);
        })
        .then((response) = > {
            fileContent = atob(response.content);
            self.files.push({
                fileName: fileName,
                fileType: fileType,
                content: fileContent
            });
            self.resultingFunction(self.files)
        }).catch ((error) = > {
            console.log('Error: ', error);
        })
});

Как заполнить self.files object после завершения цикла forEach, а затем вызовите результирующую функцию с объектом files?

4 ответов


Promise.all() будет полезно здесь:

var promises = [];

array.forEach(function(element) {
    promises.push(
        developer.getResources(element)
            .then((data) = > {
                name = data.items[0];
                return developer.getResourceContent(element, file);
            })
            .then((response) = > {
                fileContent = atob(response.content);
                self.files.push({
                    fileName: fileName,
                    fileType: fileType,
                    content: fileContent
                });
            }).catch ((error) = > {
                console.log('Error: ', error);
            })
    );
});

Promise.all(promises).then(() => 
    self.resultingFunction(self.files)
);

это запускает вызов AJAX для каждого из элементов, добавляет результат каждого вызова в self.files после завершения вызова и звонки self.resultingFunction() после завершения всех вызовов.

Edit: упрощенный на основе предложений Юрия Тарабанко.


просто небольшое изменение принятого решения выше будет:

var promises = array.map(function(element) {
      return developer.getResources(element)
          .then((data) = > {
              name = data.items[0];
              return developer.getResourceContent(element, file);
          })
          .then((response) = > {
              fileContent = atob(response.content);
              self.files.push({
                  fileName: fileName,
                  fileType: fileType,
                  content: fileContent
              });
          }).catch ((error) = > {
              console.log('Error: ', error);
          })
});

Promise.all(promises).then(() => 
    self.resultingFunction(self.files)
);

на этот ответ на аналогичный вопрос для отличной подсказки. Решение, данное там, использует Array#reduce() чтобы избежать необходимости накапливать все обещания, прежде чем делать какую-либо работу, а не использовать Promise.all().


следующий код-это простое понимание синхронизации с помощью Promise.

let numArr = [1,2,3,4,5];
let nums=[];

let promiseList = new Promise(function(resolve,reject){
  setTimeout(()=>{
        numArr.forEach((val)=>{
        nums.push(val);
    });
    resolve(nums);
 },5000)
})


Promise.all([promiseList]).then((arrList)=>{
  arrList.forEach((array)=>{
    console.log("Array return from promiseList object ",array);    
  })

 });

выше пример будет содержать array nums на 5 сек. и он будет печатать на консоли после его выпуска.