Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to wait for a promise to resolve inside a map?

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;


    });
});
like image 235
Wede Asmera Tseada Avatar asked Dec 02 '19 10:12

Wede Asmera Tseada


People also ask

How do you wait for promises to resolve?

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!

Can I use await inside map?

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.

Can you await a resolved promise?

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.


2 Answers

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(...)
like image 184
georg Avatar answered Oct 24 '22 05:10

georg


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);
})
like image 28
Kees de Kooter Avatar answered Oct 24 '22 03:10

Kees de Kooter