使用await Promise.all()后无法访问已解析Promise的属性怎么办?
问题描述
我有一个图片数组,想要一次性上传至MongoDB:
images = [{ id: 123, alt: "my image", buffer: <Buffer>, mimetype: "image/jpeg" }]
我知道应该使用Promise.all()来实现,但对Promise不太熟悉,写出了以下代码(其中Image是我的Mongoose Schema):
const uploaded_images = images.map(img => { return { id: img.id, promise: Image.create({ image: { data: img.buffer, contentType: img.mimetype }, alt: img.alt, }) }; }); await Promise.all(uploaded_images.map(img => img.promise));
但尝试访问新上传图片的_id属性时,结果是undefined:
uploaded_images.forEach(img => { console.log(img.promise); // 输出 Promise { { image: { data: new Binary(...), contentType: 'image/jpeg' }, alt: 'my image', _id: new ObjectId(...) } } console.log(img.promise._id); // 输出 Undefined })
我该如何访问_id属性?
经过进一步测试:在await Promise.all()语句前打印数组,得到 [{ id: '013150333796129177', promise: Promise { <pending> } }];在该语句后打印数组,得到[{ id: '013150333796129177', promise: Promise { [Object] } }]。这是否意味着Promise已解析?为何无法访问对象?
解决方案
问题根源
你看到的Promise { [Object] }只是Promise对象的状态展示,即使Promise已经resolve,你也不能直接通过promise._id访问结果——因为img.promise本身还是Promise实例,不是resolve后的文档对象。
正确实现方式
你需要收集Promise.all()返回的已解析结果,而不是去原数组里的Promise实例上找数据。修改代码如下:
// 先把每个图片对应的创建Promise和原id关联起来 const imagePromises = images.map(img => ({ originalId: img.id, createPromise: Image.create({ image: { data: img.buffer, contentType: img.mimetype }, alt: img.alt }) })); // 等待所有Promise完成,拿到解析后的文档数组 const uploadedDocs = await Promise.all(imagePromises.map(item => item.createPromise)); // 把原id和新的文档(包含_id)对应起来 const resultMap = uploadedDocs.map((doc, index) => ({ originalId: imagePromises[index].originalId, uploadedDoc: doc, _id: doc._id // 直接获取_id })); // 现在可以正常访问_id了 resultMap.forEach(item => { console.log(item.originalId, item._id); });
简化版实现
如果不需要保留原id和新文档的关联,直接用更简洁的写法:
const uploadedDocs = await Promise.all(images.map(img => Image.create({ image: { data: img.buffer, contentType: img.mimetype }, alt: img.alt }) )); // 直接遍历结果数组获取_id uploadedDocs.forEach(doc => { console.log(doc._id); });
补充说明
Promise.all()会返回一个数组,数组里的元素是对应位置Promise resolve后的结果,顺序和传入的Promise数组完全一致。- 即使Promise已经处于resolved状态,你也必须通过
await或者.then()来获取它的结果,不能直接从Promise实例上读取属性。
内容的提问来源于stack exchange,提问作者Oscar
相关产品推荐
相关产品推荐

