Angular 应用程序中关于返回比较和更新数组的方法链和承诺问题

Method chaining and promises issue in Angular app with regards to returning a compared and updated array

我正在尝试 filter/match 将 return 的 ID 列表编辑到 JSON 数据记录的列表,但我正在努力(我相信)我的承诺和方法链接.

我可以让这些功能正常工作,除了我在下面添加步骤 3 时。 然后它在没有匹配数据的情况下解析(该功能确实继续并最终 return 正确匹配数据,但到那时我的方法已经完成 )。

它应该是这样工作的:

  1. (getCompanyBrandProfileIDs) 首先,我的方法获取链接到当前用户的 brandProfileID。
  2. (getBrandProfiles) 然后获取 brandProfileID 并获取链接到特定 brandProfile 的所有 brandProfile。
  3. (getKeywordProfiles) 然后它应该 获取returned brandProfiles,并为每个brandProfile 获取匹配的keywordProfile。它是一个包含 brand_profile_id 和 id 的对象数组。

这是我的主要方法:

this.getCompanyBrandProfileIDs = function () {

  var brandProfileIDsToReturn = $q.defer();

  GetUserAccessService.returnBrandProfileID().then(function (brandProfileID) {

      console.log(brandProfileID);

      getBrandProfiles(brandProfileID).then(function (brandProfiles) {

          console.log(JSON.stringify(brandProfiles));

          var keywordProfilesArray = [];

          getKeywordProfiles(brandProfiles).then(function (keywordProfiles) {

              keywordProfilesArray = keywordProfiles;

              console.log(JSON.stringify(keywordProfilesArray));

              //brandProfileIDsToReturn.resolve(keywordProfilesArray);

          });

          brandProfileIDsToReturn.resolve(keywordProfilesArray);

      });

  });

  return brandProfileIDsToReturn.promise;

};

这是 getBrandProfiles 方法:

function getBrandProfiles(brandProfileID) {

  var getBrandProfilesLinkedToCompany = $q.defer();

  pullSocialMediaData('keyword_profile_brand_profiles.json?brand_profile_id=' + brandProfileID).then(function (brandProfiles) {

      var brandProfilesArray = [];

      brandProfiles.forEach(function (profile) {

          brandProfilesArray.push({ id: profile.id, name: profile.name });

      });

      getBrandProfilesLinkedToCompany.resolve(brandProfilesArray);

  });

  return getBrandProfilesLinkedToCompany.promise;

}

这是 getKeywordProfiles 方法:

function getKeywordProfiles(brandProfiles) {

      var keywordProfilesToReturn = $q.defer();

      var brandProfilesArray = brandProfiles;

      var array = [];

      brandProfilesArray.forEach(function (profile) {
          findKeywordProfile(profile.id).then(function (keywordID) {

              array.push(keywordID);
          });
          keywordProfilesToReturn.resolve(array);
      })

      return keywordProfilesToReturn.promise;

  }

这是 getKeywordProfiles 的辅助方法:

function findKeywordProfile(brandProfileID) {

  var keywordProfileID = $q.defer();

  pullSocialMediaData('list_keyword_profiles.json').then(function (data) {

      var keywordProfileInstance = data.filter(function (keyword) {
          return keyword.brand_profile_id === brandProfileID;
      });

      keywordProfileID.resolve(keywordProfileInstance[0].id);

  });

  return keywordProfileID.promise;
}

非常感谢您的帮助!

您解决 brandProfileIDsToReturn 的问题太早了。在此代码中:当您 resolve promise 时,then 回调将不会被调用,因此 keywordProfilesArray 保证为空。

this.getCompanyBrandProfileIDs = function () {
  var brandProfileIDsToReturn = $q.defer();
  GetUserAccessService.returnBrandProfileID().then(function (brandProfileID) {
      console.log(brandProfileID);
      getBrandProfiles(brandProfileID).then(function (brandProfiles) {
          console.log(JSON.stringify(brandProfiles));
          var keywordProfilesArray = [];
          getKeywordProfiles(brandProfiles).then(function (keywordProfiles) {
              keywordProfilesArray = keywordProfiles;
              console.log(JSON.stringify(keywordProfilesArray));
              //brandProfileIDsToReturn.resolve(keywordProfilesArray);
          });
          brandProfileIDsToReturn.resolve(keywordProfilesArray);
      });
  });
  return brandProfileIDsToReturn.promise;
};

只需将 resolve() 调用移动到 then 回调中即可修复它,实际上您已将该行注释掉,因此取消注释并删除其他 resolve:

this.getCompanyBrandProfileIDs = function () {
  var brandProfileIDsToReturn = $q.defer();
  GetUserAccessService.returnBrandProfileID().then(function (brandProfileID) {
      console.log(brandProfileID);
      getBrandProfiles(brandProfileID).then(function (brandProfiles) {
          console.log(JSON.stringify(brandProfiles));
          var keywordProfilesArray = [];
          getKeywordProfiles(brandProfiles).then(function (keywordProfiles) {
              keywordProfilesArray = keywordProfiles;
              console.log(JSON.stringify(keywordProfilesArray));
              brandProfileIDsToReturn.resolve(keywordProfilesArray);
          });
      });
  });
  return brandProfileIDsToReturn.promise;
};

但是,如果您停止使用 $q.defer(),您可能会大大简化代码。你的函数已经 return promises 所以只是 return 他们使用的 promises 并停止尝试创建额外的 promises。我认为这等同于之前的代码,除了它直接 returns 承诺,我删除了日志消息,这意味着 getKeywordProfiles 调用简化为只调用函数的回调,以便您可以传递函数直接:

this.getCompanyBrandProfileIDs = function () {
  return GetUserAccessService.returnBrandProfileID().then(function (brandProfileID) {
      return getBrandProfiles(brandProfileID).then(getKeywordProfiles);
      });
  });
};

然后您可以通过提取内部 .then:

进一步简化它
this.getCompanyBrandProfileIDs = function () {
  return GetUserAccessService.returnBrandProfileID()
  .then(getBrandProfiles)
  .then(getKeywordProfiles);
};

getKeywordProfiles() 函数还需要在所有 findKeywordProfile() 调用都已解决之前避免解决其承诺。 Return promise 数组的 promise,当它们 resolve 时,promise 将完成一个值数组:

function getKeywordProfiles(brandProfilesArray) {
      var array = [];
      brandProfilesArray.forEach(function (profile) {
          array.push(findKeywordProfile(profile.id));
      })
      return $q.all(array);
  }

为了澄清我对 $q 的评论,在某些情况下您需要使用它从头开始创建承诺,但这种情况并不常见。在 Angular 中异步发生的任何事情已经 return 是一个承诺,并且承诺的伟大之处在于它们链接在一起,所以当你有一个调用 .then().catch() 的承诺时return 一个新的。此外,.then() 回调可以 return 一个解析新承诺的值,或者可以 return 一个只有在它自己解析时才会解析新承诺的承诺。因此,只需将 .then() 个调用链接在一起,每个调用都会等待前一个调用完成。

$q 仍然有用:$q.all() 如果你想等待一堆承诺全部解决,$q.race() 如果你有一堆承诺并且只有一个需要要解决,$q.resolve(value) 也很有用,因为有时您只需要一个会立即解决的承诺,这样您就可以挂起其他异步函数链。

此外,即使在解决后很长时间内保持承诺也是安全的,您仍然可以对其调用 .then():如果您有异步初始化代码和事件,这可能会或可能不会在初始化完成之前触发。当你可以做 initPromise.then(...)

时不需要做 if(isInitialised)

getKeywordProfiles函数中你需要在数组循环结束时解析它。

  function getKeywordProfiles(brandProfiles) {

      var keywordProfilesToReturn = $q.defer();

      var brandProfilesArray = brandProfiles;

      var array = [];

      brandProfilesArray.forEach(function (profile) {
          findKeywordProfile(profile.id).then(function (keywordID) {

              array.push(keywordID);
          });
          //--
          //keywordProfilesToReturn.resolve(array);
      })
      //++
      keywordProfilesToReturn.resolve(array);
      return keywordProfilesToReturn.promise;
  }

Info:我认为您需要创建一个 profileIdArray 推送所有 brandProfileID 并发送到您的 findKeywordProfile 函数。会更有用。