Reputation: 428
New to promises, would like to learn. I have this array of shopIds:
let shopIdsArray = ['shop1','shop2','shop3'];
and an external promise call
getProducts(shopId, 'products') //promise returns the products of this shop
Unfortunately, the promise does not return the shopId, just the products, so I have to somehow keep the shopId and store it together with the products once the promise is finished. My current approach is to call the promise with each shopId, and add the result of each promise call to a shopsAndProductsArray like this:
shopsAndProductsArray.push({
"id":shopId,
"products":products
});
Later on, my "wrapper promise" should return the finished shopsAndProductsArray.
My current code (node, ES6) looks like:
updateProducts = new Promise(
function (resolve, reject) {
let shopIdsArray = ['shop1','shop2','shop3'];
const shopsAndProductsArray = [];
let promisesArray = [];
shopIdsArray.forEach((shopId) => {
let promise = getProducts(shopId, 'products')
.then((products) => {
const shopInfoObject = {
"id":shopId,
"products":products
};
console.log("sio: ",shopInfoObject); //prints shopIds and products fine.
shopsAndProductsArray.push(shopInfoObject);
promisesArray.push(promise);
});
});
Promise.all(promisesArray)
.then(function (shopsAndProductsArray) {
resolve(shopsAndProductsArray); //the shopsAndProductsArray is undefined?
});
}
);
On resolve, the shopsAndProductsArray is...not empty, but consists of the same number of entries as the shopIdsArray, but the array items are undefined. I probably should put the promises into an array first, then work on them in Promise.all, but at that point I lost the reference to which shop id the promise belongs.
I read many other examples about iteration and promises and tried many other ways but it seems that I haven't fully understood what is called at which point. I'm sure filling the promises array the way I do is wrong, but I had no better idea how to invoke Promise.all.
I think I could narrow my questions down to:
Thanks in advance for any help.
EDIT: Thank you so much, justelouise and Felix Kling. I knew I was overcomplicating things, but couldn't put my finger where. I understand now what I was missing, thanks to your examples. I think your answers are essentially equal and both thoroughly explained. I give the accept checkmark to justelouise because she appears to be first and Felix Kling has slightly more reputation O_o.
Upvotes: 5
Views: 4049
Reputation: 816404
Your code can be simplified a lot to:
updateProducts = Promise.all(
['shop1','shop2','shop3'].map(
id => getProducts(id, 'products').then(products => ({id, products}))
)
);
It's exactly the same approach as yours, just less verbose.
Since Promise.all
already returns a promise, there is no need to put a new Promise(...)
around it.
If you want to convert every element of an array to something else, then Array#map
is a more useful method. It applies the passed callback to every element of the array and returns an array of its return values. In your case you want to create a Promise for each shop ID, and that's what
['shop1','shop2','shop3'].map(id => getProducts(id, 'products'))
does.
Now, since you do not just want to get the products but also the ID, we have to modify the result of getProducts
a little bit, which is what the
.then(products => ({id, products}))
does. There is nothing really special about this. We simply return an object with the two properties id
and products
instead of just the products
array.
With Promise.all
and Array#map
you don't need to "manually" keep track of the promises (promisesArray
) and the results (shopsAndProductsArray
).
Upvotes: 1
Reputation: 770
I think you can simplify your functions as such:
return Promise.all(shopIdsArray.map(shopId => {
return getProducts(shopId).then((products) => {
return {
id: shopId,
products,
};
});
}));
Promise.all returns an array of promises created as you are iterating thru the array via the map function where in getProducts call is executed for each shop id. Once the products data is returned, you still have access with the corresponding shop id for it and return a new object consisting of the id and the results
return {
id: shopId,
products,
};
Lastly, Promise.all returns an array containing the returned value for each promise executed within it.
Upvotes: 11