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

IT技术 javascript arrays foreach promise es6-promise
2021-01-30 20:17:19

我在数组上运行 forEach 循环并进行两次返回Promise的调用,我想填充一个对象 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在 forEach 循环完成后填充对象,然后使用文件对象调用结果函数?

5个回答

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 的建议进行简化。

应该是Promise.all,而不是Promise(复数)。
2021-03-15 20:17:19
啊,我明白了。今天学到了新东西!谢谢 :-)
2021-03-20 20:17:19
@TimoSta 不是直接来自,getResources而是您在链中获得的最后一个PromisegetResources().then(fn1).then(fn2).catch()每次你打电话then都会得到一个新的Promise。并且肯定fn1fn2在完成处理程序之前和之前被调用仅仅是因为Promise会将 fn1 的结果传递给 fn2,然后传递给终结处理程序(作为相应的数组元素)。
2021-03-21 20:17:19
@YuryTarabanko 出于好奇,如果您将getResources直接返回的Promise推送到promises数组而不是将其包装在您自己数组中,是否可以保证在Promise.all()? 如果没有,创建自己的Promise似乎是必要的。
2021-03-23 20:17:19
为什么要手动创建 Promise?这一切看起来getResources已经返回了一个
2021-04-10 20:17:19

上面接受的解决方案的一个轻微变化是:

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

在最后添加了一个新句子来解释我做了什么。
2021-03-21 20:17:19
您能否突出显示您所做的更改,以便我们不必阅读每一行?
2021-03-22 20:17:19

您可能会查看对类似问题的回答以获得极好的提示。那里给出的解决方案Array#reduce()用于避免在执行任何工作之前必须累积所有 Promises 而不是使用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);    
  })

 });

上面的示例将保存数组 nums 5 秒。它会在发布后打印在控制台上。

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

await Promise.all([...arr.map(i => "our promise func"())]);
虽然此代码可能会回答问题,但提供有关此代码为什么和/或如何回答问题的附加上下文可提高其长期value。
2021-03-19 20:17:19