如何将 forEach 与 Promises.all 结合起来



我正在执行一个函数,该函数将图像从输入文件字段上传到AWS,然后将图像URL和名称保存到mongoDB。我正在使用NodeJS和MongoDB。这是我的例子:

uploadFile(req, res, next) {
let files = req.files;
let images = [];

files.file.forEach((file) => {
uploadToAWS(file.path, {}, function(err, img) {
if (err) { throw err; }
// add path and name to images array
images.push({
path: img[0].url,
name: img[0].name,
});
});
});
// Here the promises should resolve and save to MongoDB the array images
},

我不是每次循环遍历元素时都保存到数据库中,而是填充一个数组images然后将其保存到数据库。

为此,您希望使用 Array#map() 而不是 Array#forEach。这是因为您打算根据每个值将某些值映射到承诺。

return Promise.all(files.map((file) => {
// do some stuff with each file here
}));

一个完整的示例如下所示:

uploadFile(req, res, next) {
let files = req.files;
let images = [];
const promises = files.file.map((file) => {
return uploadToAWS(file.path, {}).then((img) => {
// add path and name to images array
images.push({
path: img[0].url,
name: img[0].name,
});
});
});
// Here the promises should resolve and save to MongoDB the array images
Promise.all(promises).then(next);
}

请注意,在这里,我假设uploadToAws()能够返回一个承诺,因为这是完成这项工作所必需的,否则

纸牌屋的承诺就会崩溃。如果没有内置的uploadToAws()承诺支持,您可以使用像 pify 这样的promisify实用程序将函数包装为适配器,该适配器将根据回调的结果为您创建承诺。

资源

  • http://2ality.com/2014/10/es6-promises-api.html
  • http://2ality.com/2016/10/async-function-tips.html

您可以使用Bluebird的promisify来制作您的uploadToAWS()返回一个承诺而不是接受回调(你也可以在没有promisify的情况下轻松做到这一点,但它很有用),因为如果你想使用 Promise.all 等,使用返回承诺的函数要容易得多。如果要使用接受回调的函数,那么我建议使用异步模块来管理控制流。

当你承诺你的uploadToAWS()那么你将能够做这样的事情:

let promises = files.file.map(file => uploadToAWS(file.path, {}));

然后,您将能够使用:

Promise.all(promises)
.then((imgs) => {
// everything succeeded
}).catch((error) => {
// there was an error
});

或者,如果您使用的是异步/等待:

try {
let imgs = await Promise.all(promises);
// everything succeeded
} catch (error) {
// there was an error
}

现在,只要您有imgs它都是uploadToAWS()返回的对象数组(或者,严格来说,在所有这些承诺都已解析后由uploadToAWS()返回的解析值数组)。

您可以使用该数组创建另一个数组,例如您的images

let images = imgs.map(img => ({
path: img[0].url,
name: img[0].name,
});

或:

let images = imgs.map(img => ({
path: img.url,
name: img.name,
});

取决于uploadToAWS()实际返回的内容,因为您没有指定。

但请记住,当您遇到错误时,您需要通过删除不再需要的上传文件来从中恢复。

最新更新