在开始之前,我完全没有完全理解 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()
谢谢。
答案 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)
);
}