Reputation: 1058
So I have an asynchronous function that I need to call a number of times. Naturally, I would like to use Promise.all
const promises = [];
ids.forEach((id) => {
stockoutPromises.push(
asyncFunc(id),
});
});
results[] = Promise.all(promises);
Okay no problem there but how do I know which id goes with which result? Sure I could iterate through both arrays again, but is there another way to do this? Is there a way that I can create a promise that when resolved gives me an object that contains both id and result?
Thanks!
Upvotes: 1
Views: 1861
Reputation: 148
Instead of using forEach, use map:
const promises = ids.map((id) => {
return asyncFunc(id)
});
const results = await Promise.all(promises);
map
will return a new array of objects based on what the supplied function returns. In your case, you are calling an asyncFunc
, which, I assume, returns a promise itself. So you can just return the results of map directlty without pushing to a new promises array.
Also, make sure to "await" the call to Promise.all
;
You can check it out here in this jsfiddle that simply has the asyncFunc
return a promise that doubles the id in the ids
array.
Upvotes: 0
Reputation: 64657
The result of Promise.all
will be in the order that they were in originally (in the array of promises). So you can easily reassociate just using the index:
// zip takes an array of keys, and an array of values, and creates an object:
const zip = (a, b) => Object.fromEntries(a.map((k, i) => [k, b[i]]));
// first id will resolve last, second will resolve next, etc.
const ids = [0, 1, 2, 3, 4];
const promises = ids.map((i) => new Promise((resolve) => {
setTimeout(() => resolve(i), 700 - (100 * i));
}));
// but we still get the correct item in each spot, because of how
// Promise.all works:
(async () => {
console.log(zip(ids, await Promise.all(promises)));
})()
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all:
Returned values will be in order of the Promises passed, regardless of completion order.
Upvotes: 0
Reputation: 370729
Chain a .then
onto the call of asyncFunc
so that the resulting item is not just of the asyncFunc
result, but of it and the ID in an object:
ids.forEach((id) => {
stockoutPromises.push(
asyncFunc(id).then(result => ({ id, result }))
);
});
But it'd be better to use .map
instead of .push
in a loop:
const results = await Promise.all(
ids.map(id =>
asyncFunc(id).then(result => ({ id, result }))
)
);
const firstItem = results[0];
console.log(firstItem.result, firstItem.id);
Upvotes: 3