在循环中等待承诺

时间:2018-01-05 10:05:05

标签: javascript angularjs foreach

使用AngularJs时,使用forEach循环时,循环外的变量仍为0: 解释我的问题,这是我的代码

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});

                });

                });

在forEach之后,当我执行console.log(totald)时,我得到0.但是当我将console.log放在forEach中时,变量totald会递增。

如何解决问题并在forEach完成后获得正确的totald值

3 个答案:

答案 0 :(得分:4)

您可以将每个承诺映射为列表,并使用$q.all等待所有承诺。

这样的事情:

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});
    });
};

答案 1 :(得分:1)

您应该考虑以功能样式重写此代码;它会更具可读性:

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
});

最重要的变化是使用map而不是forEach。使用forEach从来没有真正的理由,因为for (... of ...)构造更清楚地表明了副作用。 map也更紧凑:

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

vs ...

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

如果您担心async-await的浏览器支持,那么您可以使用Babel + Webpack。

答案 2 :(得分:0)

您可以使用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});    
    });
});