Reputation: 317
How to access an item in an object that is returned from Promise.all()
.
I want to iterate throughout the array and get the title returned from each promise, but I can't access Promise {}
and then any of the object inside.
[
Promise {
{
_id: 5e09e4e0fcda6f268cefef3f,
title: 'dfgfdgd',
shortDescription: 'gfdgdfg'
},
qty: 1
},
Promise {
{
_id: 5e09e507fcda6f268cefef40,
title: 'Test product',
shortDescription: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the '
},
qty: 1
},
Promise {
{
_id: 5e09e507fcda6f268cefef40,
title: 'Test product',
shortDescription: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the '
},
qty: 3
}
]
This is the code that creates promise array
const userId = req.user._id;
try {
const user = await User.findById(userId);
const { inCart } = user;
const results = [];
for (let i = 0; i < inCart.length; i += 1) {
results.push(Product.findById(inCart[i].itemId, 'title shortDescription').exec());
}
await Promise.all(results);
for (let i = 0; i < results.length; i += 1) {
results[i].qty = inCart[i].qty;
}
return res.render('shop/cart', { items: results });
} catch (error) {
console.log(error)
}
Upvotes: 3
Views: 978
Reputation: 664464
results
is an array of promises, and it will stay that array of promises - Promise.all
doesn't alter the array. It creates a new array with the result values, which is what your await
expression will yield. You should use
const userId = req.user._id;
try {
const user = await User.findById(userId);
const { inCart } = user;
const promises = [];
for (const item of inCart) {
promises.push(Product.findById(item.itemId, 'title shortDescription').exec());
// ^^^^^^^^
}
const results = await Promise.all(promises);
// ^^^^^^^^^ ^^^^^^^^
// drop the qty assignment completely
return res.render('shop/cart', { items: results });
} catch (error) {
console.log(error)
}
Upvotes: 2
Reputation: 15166
I guess with Promise.all
there is no chance to figure out which one called already the resolve
function inside.
From Promise.all()
documentation which states:
The Promise.all() method returns a single Promise that fulfills when all of the promises passed as an iterable have been fulfilled or when the iterable contains no promises. It rejects with the reason of the first promise that rejects.
In my example I have created the Promise
elements with simpler objects like { title: 'first' }
for better representation.
To achieve your goal what is in your requirement, you need handle each Promise
resolved state for example in a forEach
just like in my solution instead of using Promise.all()
. And by using then
on each iteration you can access the object's properties which has been resolved.
Instead you can do something like this - obviously you need to apply to your structure:
const promises = [
new Promise(resolve => {
setTimeout(() => {
resolve({ title: 'first' })
}, 1200)
}),
new Promise(resolve => {
setTimeout(() => {
resolve({ title: 'second' })
}, 800)
}),
new Promise(resolve => {
setTimeout(() => {
resolve({ title: 'third' })
}, 2400)
}),
new Promise(resolve => {
setTimeout(() => {
resolve({ title: 'fourth' })
}, 3200)
}),
];
Promise.all(promises).then(() => console.log('all finished'));
promises.forEach(p => p.then(d => console.log(`${d.title} finished`)));
I hope that clarifies and help!
Upvotes: 3
Reputation: 30
First, you need to await
the promises then you can get an array that contains objects
async function getData(){
try{
const data = await Promise.all()
data[0].title // result : dfgfdgd
}catch(e){
// handle errors
}
}
Upvotes: 0
Reputation: 1074268
Promise.all
returns a promise. The only way to get the fulfillment value of a promise is by using a fulfillment handler.
I want to iterate throughout the array and get the title of each promise
Promises don't have titles. Fulfillment values might, if they're objects with a title
property.
So for instance:
thePromise
.then(results => {
// ...use `results` (an array) here...
for (const {title} of results) {
// ...use `title` here, it's each title in the array of objects...
}
})
.catch(error => {
// ...handle/report error here...
});
Or inside an async
function:
try {
const results = await thePromise;
for (const {title} of results) {
// ...use `title` here, it's each title in the array of objects...
}
} catch (error) {
// ...handle/report error here...
}
(Or for (const {title} of await thePromise)
, you don't actually need the results
constant if you don't want it.)
Upvotes: 2