I have a list of objects that I want to process. The object is passed to a promise function that does this and that and resolves back. The process could be instant or not, based on previously cached value. If there is already calculated value, it will resolve to it instantly. Else, it will calculate. Now the issue I am having is that the next object is passed to the promise before the first object's status is calcualted:
let people = [
{groupId: 1, name: 'Jessica Coleman', status: 'Unknown', id:1}
{groupId: 1, name: 'Eric Tomson', status: 'Unknown', id:2}
{groupId: 1, name: 'Samuel Bell', status: 'Unknown', id:3}
];
now I want to absolutely wait for the promise to resolve during loop even if the promise takes a minute to calculate on the very instance. All people with the same group have the same status. Hence, the promise checks if a group has already been calculated. If yes, returns it. Else, it calculates. and that's where the issue lies. Before Jessica 1 is finished, the other people are passed.
people.map(function(person) {
// return the promise to array
this.calculatorService
.getStatus(person)
.then(function(res) {
person.status = res;
});
});
You can use the async/await syntax or call the . then() method on a promise to wait for it to resolve. Inside of functions marked with the async keyword, you can use await to wait for the promises to resolve before continuing to the next line of the function. Copied!
If you use the async await function and console out the output, then you will find the arrays of promises that are still needed to be resolved. The map doesn't resolve the promises on its own but left the stuff for the developer to resolve. So, that means you can't use async-await in the map.
await is a new operator used to wait for a promise to resolve or reject. It can only be used inside an async function. Promise. all returns an array with the resolved values once all the passed-in promises have resolved.
Array iterators like map
or forEach
don't work with promises because they don't know how to await a result. Use a simple for
loop instead:
for (let person of people)
person.status = await this.calculatorService.getStatus(person)
If you really want a "functional" way (and avoid explicit async/await), you can define a function similar to the bluebird's Promise.each
:
Promise.each = function(ary, fn) {
return ary.reduce((p, x) => p.then(() => fn(x)), Promise.resolve(null))
}
and apply it like this:
function setStatus(person) {
return calculatorService
.getStatus(person)
.then(res => person.status = res);
}
Promise.each(people, setStatus).then(...)
Make it work synchronously with async/await
. (for..of
would be better suited than .map
in this case btw).
for (let person of people) {
person.status = await this.calculatorService.getStatus(person);
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With