angular 中的异步事件有问题

Trouble with asynchronous events in angular

我的代码循环遍历数组中的 10 个项目,对每个项目发出请求,然后将返回的数据推送到一个数组。一切运行正常,直到 $q.all 行。

details.getDetails = function(idSet, pageNum) {
  var page = idSet[pageNum],
      mainDeferred = $q.defer(),
      promises = [],
      combinedItems = [];

  for(var i=0; i<page.length; i++){
    var deferred = $q.defer();
    ngGPlacesAPI.placeDetails({placeId: page[i][i]})
      .then(function(data){
        combinedItems.push(data);
        console.log(combinedItems); /// This shows the objects being pushed into the array
        deferred.resolve();
      });

    promises.push(deferred.promise);
  }

  console.log(promises); /// This shows the 10 promises

  $q.all(promises).then(function() { /// Nothing after this line runs
    console.log('test', mainDeferred.promise); /// This logs nothing
    mainDeferred.resolve(combinedItems);
  });
  return mainDeferred.promise;
};

在 javascript 中处理异步时,这是一个非常常见的错误。

应该问的问题是:"when the resolver (the function you pass to .then) looks up the variable deferred, what variable does it get back?"。那么答案是,它们都引用了您声明的最后一个 deferred

问题是,您在解析函数之外声明 deferred。记住 javascript 如何查找变量:

  1. 变量(在我们的例子中,deferred)在直接函数范围内可用吗? (在我们的例子中,没有)
  2. 向上遍历父作用域,直到找到具有给定名称的变量。

解析器启动时,您已重新声明 deferred 10 次,每次声明都会覆盖前一次声明!所以每次解析器触发时,它实际上解析了 same deferred!

答案是将您的 deferred 声明包装在闭包中:

for(var i=0; i<page.length; i++){
  (function(){
    var deferred = $q.defer();
    ngGPlacesAPI.placeDetails({placeId: page[i][i]})
      .then(function(data){
        combinedItems.push(data);
        console.log(combinedItems); /// This shows the objects being pushed into the array
        deferred.resolve();
      });
    promises.push(deferred.promise);
  })()
}

但实际上,您可以简化整个程序并避免延迟。如果这对你有意义,请告诉我!:

details.getDetails = function(idSet, pageNum) {
  var page = idSet[pageNum];

  // generate an array from 0 to page.length
  var items = Array.apply(null, { length: page.length })

  var promises = items.map(function (i) {
    return ngGPlacesAPI.placeDetails({placeId: page[i][i]});
  })

  return $q.all(promises)
};