Angular 循环承诺 - 函数 Returns 空对象

Angular Looping Promises - Function Returns Empty Object

我正在尝试将结果(数组)从 promise 传递到迭代此结果的函数,为每个项目发出 get 请求并在 returning 之前使用结果创建一个新对象它。问题是在解决承诺并填充它之前,正在 returned 对象。从多个承诺中 return 填充对象的正确方法是什么?

function getPackageDetails(packages) {
  var detailedPackages = {};
  angular.forEach(packages, function(p) {
    vsmsPackageFactory.getPackage(p.id)
    .then(function(response) {
      var subsystem = response.data.packageManifest.subsystem;
      var partNumber = response.data.packageManifest.resultConfig.partNumber;
      var packageName = response.data.packageMetaData.packageName;
      if(detailedPackages[subsystem] === undefined) {
        detailedPackages[subsystem] = {};
      }
      if(detailedPackages[subsystem][partNumber] === undefined) {
        detailedPackages[subsystem][partNumber] = {};
      }
      detailedPackages[subsystem][partNumber][packageName] = response.data;
    });
  });
  return detailedPackages; // returns before all promises resolved
}

vsmsCampaignFactory.getCampaignPackages(queryString)
.then(function(response) {
  vm.packageList = getPackageDetails(response.results);
});

对于这样的情况,您应该考虑使用 $q.all,在这种情况下,您可以将所有承诺收集在单个承诺数组中,然后将其传递给 $q.all 和 return 结果承诺。它将确保您在完成所有承诺后 returning data

在您的代码中,您只是在执行异步 ajax 调用,而不用担心它们是否完成。紧接着您正在 returning detailedPackages 数据。但显然它会是空的。

代码

function getPackageDetails(packages) {
  var detailedPackages = {};
  var promises = []; //promise array
  angular.forEach(packages, function(p) {

    var promise = vsmsPackageFactory.getPackage(p.id)
    .then(function(response) {
      var subsystem = response.data.packageManifest.subsystem;
      var partNumber = response.data.packageManifest.resultConfig.partNumber;
      var packageName = response.data.packageMetaData.packageName;
      if(detailedPackages[subsystem] === undefined) {
        detailedPackages[subsystem] = {};
      }
      if(detailedPackages[subsystem][partNumber] === undefined) {
        detailedPackages[subsystem][partNumber] = {};
      }
      detailedPackages[subsystem][partNumber][packageName] = response.data;
    });
    promises.push(promise);
  });
  return $q.all(promises).then(function(){
    return detailedPackages;  // returned data after all promises are done
  });
}

这可以使用 promise all 来实现,here

 var promises = [];
 promises.push(new Promise(function (resolve, reject) {
   vsmsPackageFactory.getPackage(p.id)
    .then(function(response) {
     ...
     resolve('If you want to return something')
    });
 });
 //After the loop it's finished you execute your promises
 Promise.all(promises).then(function (values) {
  ... perform more code
 });