TL;DR: Map each item in the array to a fetch call and wrap them around Promise.all()
.
Promise.all(
this.cartProducts.map(p =>
fetch(`/api/products/getDetails/${p.clientId}`).then(res => res.json())
)
).then(products => console.log(products));
Explanation
fetch()
returns a Promise
a.k.a "I promise I'll give you a value in the future". When the time comes, that future value is resolved and passed to the callback in .then(callback)
for further processing. The result of .then()
is also a Promise
which means they're chainable.
// returns Promise
fetch('...')
// also returns Promise
fetch('...').then(res => res.json())
// also returns Promise where the next resolved value is undefined
fetch('...').then(res => res.json()).then(() => undefined)
So the code below will return another Promise
where the resolved value is a parsed Javascript object.
fetch('...').then(res => res.json())
Array.map()
maps each item to the result of the callback and return a new array after all callbacks are executed, in this case an array of Promise
.
const promises = this.cartProducts.map(p =>
fetch("...").then(res => res.json())
);
After calling map, you will have a list of Promise
waiting to be resolved. They do not contains the actual product value fetched from the server as explained above. But you don't want promises, you want to get an array of the final resolved values.
That's where Promise.all()
comes into play. They are the promise version of the Array.map()
where they 'map' each Promise
to the resolved value using the Promise
API.
Because of that Promise.all()
will resolve yet another new Promise
after all of the individual promises in the promises
array have been resolved.
// assuming the resolved value is Product
// promises is Promise[]
const promises = this.cartProducts.map(p =>
fetch("...").then(res => res.json())
);
Promise.all(promises).then(products => {
// products is Product[]. The actual value we need
console.log(products)
})