异步等待承诺在节点中使用循环

时间:2021-07-27 15:15:54

标签: javascript node.js arrays promise

在开始之前,我完全没有完全理解 node / javascript 中异步编程的复杂性。

我有一个包含图像 URL 和输出名称的多维数组。我正在尝试使用sharp遍历它们,下载,操作和输出它们。我想要做的是捕获形状作为错误抛出的任何损坏的图像,更新数组并在任务完成后继续对数组执行操作。

我遇到的问题是我的代码没有等待集成完成,因此没有继续更新数组。

这是我正在使用的代码类型:

let imgArr = [['url1', 'url2', 'url3', 'url4'],['name1', 'name2', 'name3', 'name4']]

function saveImg(url, output)
    return new Promise(async(resolve, reject) => {
       axios.get(url, { responseType: 'arraybuffer' })
       .then((res) => {
          sharp(res.data)
          .resize({changing size etc})
          .png({quality: 95})
          .toFile(output)
          .then(() => { resolve() })
          .catch((err) => { reject() })
    })
}

function processImg(obj){
   return new Promise(async(resolve, reject) => {
      for(let i = 0; i < obj.length; i++){
         saveImg(obj[i][0], obj[i][1])
         .catch((err) => {
             imgArr[i][1] = 'image-not-found.png'
         })
      }
      resolve()
   })
 }

async function doStuff(){
     processImg(imgArr)
        .then(() => {
            console.log(imgArr) // this is where I'd hoped the updated array would appear
        })
        .catch((err) => {
            console.log(err)
        })
)

doStuff()

谢谢。

1 个答案:

答案 0 :(得分:1)

当你像这样在 for 循环中执行 promise 时,它​​们都是并行开始的。然后在承诺真正解决之前立即调用 resolve()

您可以使用 Promise.all(或@funkizer 在评论中建议的 Promise.allSettled)来解决此问题:

function processImg(obj){
   return new Promise(async(resolve, reject) => {
      Promise.allSettled(obj.map((item, i) =>
         saveImg(item[0], item[1])
         .catch((err) => {
             imgArr[i][1] = 'image-not-found.png'
         })
      )).then(resolve)
   })
 }

但是new Promise 中的这种包装不是必需的;可以直接返回promise,如下:

function processImg(obj){
   return Promise.allSettled(obj.map((item, i) =>
      saveImg(item[0], item[1])
      .catch((err) => {
          imgArr[i][1] = 'image-not-found.png'
      })
   );
}

您可以类似地简化saveImg

function saveImg(url, output)
    return
       axios.get(url, { responseType: 'arraybuffer' })
       .then((res) =>
          sharp(res.data)
          .resize({changing size etc})
          .png({quality: 95})
          .toFile(output)
       );
}