在Angular的异步中遇到一些麻烦。基本上,我正在循环几张牌。某两种类型的卡需要API调用,而不属于这些类型的卡则不需要任何API调用。循环遍历所有卡后,返回完成的卡片阵列,但我只返回那些不需要任何API调用的卡片。
这是我对其工作方式的快速模型:
// If color of colorCard is blue, it needs 2 API calls
// If color of colorCard is red, it needs 1 API call
// If color of colorCard is yellow, it doesn't need an API call
// Pretend for this example that colorCards has one yellow card, one blue card, and two red cards
var buildCards = function() {
var finishedArray = [];
var promises = [];
colorCards.forEach(function(e, i){
if (e.color === 'blue') {
promises.push(firstBlueApiCall);
var firstBlueIdx = 0;
promises.push(secondBlueApiCall);
var secondBlueIdx = 1;
} else if (e.color === 'red') {
promises.push(redApiCall);
var redIdx = 0;
}
// If card is blue or red, complete API calls before pushing to finishedArray
if (promises.length > 0) {
$q.all(promises).then(function(response) {
if (e.color === 'blue') {
e.firstBlueData = response[firstBlueIdx];
e.secondBlueData = response[secondBlueIdx];
} else if (e.color === 'red') {
e.redData = response[redIdx];
}
finishedArray.push(e);
promises = [];
});
// If card is yellow, push to finishedArray without making any API calls
} else {
finishedArray.push(e);
promises = [];
}
})
return finishedArray;
}
在此示例中,仅返回的finishedArray包含一张不需要API调用的黄牌,而不是所有四张牌。我怎样才能得到'return finishedArray'等到红/蓝卡完成他们的API调用?
答案 0 :(得分:1)
buildCards
功能可以简化:
var buildCards = function(colorCards) {
//var deferred = $q.defer();
//var finishedArray = [];
var promises = [];
colorCards.forEach(function(card, i){
promises.push(promiseFunction(card));
});
//$q.all(promises).then(function(finishedCards) {
// deferred.resolve(finishedCards)
//})
//return deferred.promise;
return $q.all(promises);
}
由于$q.defer
方法已经返回一个承诺,因此无需使用$q.all
制作承诺。此外,制造的承诺不能正确处理拒绝。如果任何$q.all
承诺遭到拒绝,则$q.defer
承诺将会挂起并永不解决。
这被称为Deferred Anti-Pattern,应该避免使用。
同样,可以修改promiseFunction
函数以避免Deferred Anti-Pattern:
var promiseFunction = function(card){
//var deferred = $q.defer();
var localPromises = [];
if (card.color === 'blue') {
localPromises.push(blueApiCall1); var firstBlueIdx = promises.length - 1;
localPromises.push(blueApiCall2); var secondBlueIdx = promises.length - 1;
} else if (card.color === 'red') {
localPromises.push(redApiCall); var redIdx = promises.length - 1;
}
var cardPromise;
if (localPromises.length > 0) {
//$q.all(promises).then(function(res) {
cardPromise = $q.all(localPromises).then(function(res) {
if (card.color === 'blue') {
card.firstBlueData = res[firstBlueIdx];
card.secondBlueData = res[secondBlueIdx];
} else if (card.color === 'red') {
card.redData = res[redIdx];
}
//deferred.resolve(card);
//RETURN value to chain
return card;
});
} else {
//deferred.resolve(card);
cardPromise = $q.when(card);
}
//return deferred.promise;
return cardPromise;
}
promise的then
方法总是返回一个新的promise,它解析为返回给处理函数的值。此外,如果原始承诺被拒绝,则将跳过成功处理程序,拒绝将在链中传递给新承诺。这可以避免错误地挂起$q.defer
。
另请注意,如果没有承诺可以使用$q.all
进行处理,则可以使用cardPromise
创建$q.when
。
因为调用promise的.then
方法会返回新派生的promise ,所以很容易创建一个promises链。可以创建任何长度的链,并且由于可以使用另一个承诺(将进一步推迟其解析)来解决承诺,因此可以在链中的任何点暂停/推迟承诺的解析。这使得实现强大的API
- AngularJS $q Service API Reference - Chaining Promises
始终保证承诺。避免使用Deferred Anti-Pattern。
答案 1 :(得分:0)
以下是我最终解决这个问题的方法:
mClusterManager.cluster()
我试图做到这一点,它的承诺一路下来,而且效果很好。希望这有助于将来遇到类似问题的人。