Majdi Taleb
Majdi Taleb

Reputation: 761

waiting for Promise in a Loop

Using AngularJs, when using a forEach Loop, the variable outside the loop still always 0: to explain my problem, this is my code

var totald=0;
   children.forEach(function (child) {
                   fetchdata(child['id']).then(function (resp) {
                    totald+= resp.total;
                    domaines.push({'id': child['id'], 'total': resp.total, 'details': resp.details});

                });

                });

After forEach, when I do console.log(totald), I get 0. but when I put console.log inside the forEach, the variable totald is incremented.

How I can resolve the problem and get the correct value of totald after the forEach finishied

Upvotes: 0

Views: 118

Answers (3)

sdgfsdh
sdgfsdh

Reputation: 37045

You should consider rewritting this code in a functional style; it will be much more readable:

const promises = children.map(async (child) => {
  const response = await fetchdata(child['id']);
  return { 
    id: child['id'], 
    response 
  };
});

const results = await Promise.all(promises);

const total = results.map(result => result.response.total)
  .reduce((x, y) => x + y, 0);

const domains = results.map(result => ({
  id: result.id, 
  total: result.response.total, 
  details: result.response.details
});

The most significant change is using map instead of forEach. There is never really a reason to use forEach because the for (... of ...) construct more clearly suggests side-effects. map is also more compact:

const ys = xs.map(x => x + 1);

vs...

const ys = [];
xs.forEach(x => {
  ys.push(x + 1);
})

If you are concerned about browser-support for async-await then you can use Babel + Webpack.

Upvotes: 1

Nikolaj Dam Larsen
Nikolaj Dam Larsen

Reputation: 5674

You can map each promise as a list and await all of them using $q.all.

Something like this:

var totald = 0;
var promises = children.map(function (child) {
    return fetchdata(child['id']).then(function(response){
        return { id: child['id'], response: response };
    });
});

$q.all(promises).then(function(results)){
    results.forEach(function(result){
        totald += result.response.total;
        domaines.push({'id': result.id, 'total': result.response.total, 'details': result.response.details});
    });
};

Upvotes: 4

Faly
Faly

Reputation: 13356

You can use Promise.all:

var total = 0;            
Promise.all(
    children.map(function(c) { return fetchdata(child['id']); })
).then(function(datas) {
    datas.forEach(function(data) {
        total += data.total;
        domaines.push({'id': child['id'], 'total': data.total, 'details': data.details});    
    });
});

Upvotes: 0

Related Questions