如何在forEach循环数组中使用promise来填充对象

时间:2016-07-13 21:45:32

标签: javascript arrays foreach promise es6-promise

我在一个数组上运行一个forEach循环并进行两次返回promises的调用,我想填充一个对象说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);
        })
});

如何在forEach循环完成后填充self.files对象,然后使用files对象调用生成的函数?

5 个答案:

答案 0 :(得分:51)

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()

修改:根据Yury Tarabanko的建议进行简化。

答案 1 :(得分:18)

上面接受的解决方案只是略有变化:

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.map代替Array.forEach,这意味着我不需要先创建一个空数组,我只是重新使用现有的数组。

答案 2 :(得分:1)

您可以查看this answer to a similar question的优秀提示。给出的解决方案使用Array#reduce()来避免在执行任何工作之前累积所有Promise而不是使用Promise.all()

答案 3 :(得分:1)

以下代码使用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);    
  })

 });

以上示例将保持数组 nums 5秒。它会在发布后在控制台上打印出来。

答案 4 :(得分:0)

您可以使用.map作为一个循环,对数组中的每个元素启动Promise请求,并返回这些Promise的新数组。 我也使用了解构,但不确定我们在这里需要它。

await Promise.all([...arr.map(i => "our promise func"())]);