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 正确匹配数据,但到那时我的方法已经完成 )。
它应该是这样工作的:
- (getCompanyBrandProfileIDs) 首先,我的方法获取链接到当前用户的 brandProfileID。
- (getBrandProfiles) 然后获取 brandProfileID 并获取链接到特定 brandProfile 的所有 brandProfile。
- (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 函数。会更有用。
我正在尝试 filter/match 将 return 的 ID 列表编辑到 JSON 数据记录的列表,但我正在努力(我相信)我的承诺和方法链接.
我可以让这些功能正常工作,除了我在下面添加步骤 3 时。 然后它在没有匹配数据的情况下解析(该功能确实继续并最终 return 正确匹配数据,但到那时我的方法已经完成 )。
它应该是这样工作的:
- (getCompanyBrandProfileIDs) 首先,我的方法获取链接到当前用户的 brandProfileID。
- (getBrandProfiles) 然后获取 brandProfileID 并获取链接到特定 brandProfile 的所有 brandProfile。
- (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 函数。会更有用。