lulu33
lulu33

Reputation: 317

How to access key returned from Promise.all()

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
  }
]

EDIT

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

Answers (4)

Bergi
Bergi

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

norbitrial
norbitrial

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

Ziad Abouelfarah
Ziad Abouelfarah

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

T.J. Crowder
T.J. Crowder

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

Related Questions