问题描述
提供以下功能:
function isGood(number) {
var defer = $q.defer();
$timeout(function() {
if (<some condition on number>) {
defer.resolve();
} else {
defer.reject();
}
}, 100);
return defer.promise;
}
和数字数组(例如[3, 9, 17, 26, 89]
),我想找到第一个好"数字.我希望能够做到这一点:
var arr = [3, 9, 17, 26, 89];
findGoodNumber(arr).then(function(goodNumber) {
console.log('Good number found: ' + goodNumber);
}, function() {
console.log('No good numbers found');
});
function findGoodNumber(numbers) {
var defer = $q.defer();
if (numbers.length === 0) {
defer.reject();
} else {
var num = numbers.shift();
isGood(num).then(function() {
defer.resolve(num);
}, function() {
findGoodNumber(numbers).then(defer.resolve, defer.reject)
});
}
return defer.promise;
}
我想知道是否有更好的(也许是非递归的)方法?
是的.避免使用递延反模式!
!function isGood(number) {
return $timeout(function() {
if (<some condition on number>) {
return number; // Resolve with the number, simplifies code below
} else {
throw new Error("…");
}
}, 100);
}
function findGoodNumber(numbers) {
if (numbers.length === 0) {
return $q.reject();
} else {
return isGood(numbers.shift()).catch(function() {
return findGoodNumber(numbers);
});
}
}
您可以制定一个循环,该循环链接许多then
调用,但是在这里绝对可以使用递归.如果您真的想要循环,它可能看起来像这样:
function findGoodNumber(numbers) {
return numbers.reduce(function(previousFinds, num) {
return previousFinds.catch(function() {
return isGood(num);
});
}, $q.reject());
}
然而,这效率较低,因为它总是查看所有numbers
. 递归"版本将对其进行延迟评估,并且仅在当前数字不好的情况下才进行另一次迭代.
您可以并行触发所有isGood
检查,并等待第一个完成的检查返回.根据isGood
的实际功能以及可并行性的不同,这可能会更好".但是,它可能会做很多不必要的工作.您可能要使用支持取消的Promise库.
使用Bluebird库的示例,该库具有 any
辅助函数专门用于此任务:
function findGoodNumber(numbers) {
return Bluebird.any(numbers.map(isGood))
}
Given the following function:
function isGood(number) {
var defer = $q.defer();
$timeout(function() {
if (<some condition on number>) {
defer.resolve();
} else {
defer.reject();
}
}, 100);
return defer.promise;
}
and an array of numbers (e.g. [3, 9, 17, 26, 89]
), I would like to find the first "good" number. I would like to be able to do this:
var arr = [3, 9, 17, 26, 89];
findGoodNumber(arr).then(function(goodNumber) {
console.log('Good number found: ' + goodNumber);
}, function() {
console.log('No good numbers found');
});
Here is one possible recursive version to implement this:
function findGoodNumber(numbers) {
var defer = $q.defer();
if (numbers.length === 0) {
defer.reject();
} else {
var num = numbers.shift();
isGood(num).then(function() {
defer.resolve(num);
}, function() {
findGoodNumber(numbers).then(defer.resolve, defer.reject)
});
}
return defer.promise;
}
I wonder if there is a better (maybe non-recursive) way?
Yes. Avoid the deferred antipattern!
function isGood(number) {
return $timeout(function() {
if (<some condition on number>) {
return number; // Resolve with the number, simplifies code below
} else {
throw new Error("…");
}
}, 100);
}
function findGoodNumber(numbers) {
if (numbers.length === 0) {
return $q.reject();
} else {
return isGood(numbers.shift()).catch(function() {
return findGoodNumber(numbers);
});
}
}
You can formulate a loop that chains lots of then
calls, however recursion is absolutely fine here. If you really wanted the loop, it might look like this:
function findGoodNumber(numbers) {
return numbers.reduce(function(previousFinds, num) {
return previousFinds.catch(function() {
return isGood(num);
});
}, $q.reject());
}
This is however less efficient, as it always looks at all numbers
. The "recursive" version will evaluate it lazily, and only do another iteration if the current number was not good.
You can fire all isGood
checks in parallel, and wait for the first fulfilled to return. Depending on what isGood
actually does and how well that is parallelizable, this might be "better". It potentially does a lot of unnecessary work, though; you may want to use a promise library that supports cancellation.
An example using the Bluebird library, which has a any
helper function dedicated to this task:
function findGoodNumber(numbers) {
return Bluebird.any(numbers.map(isGood))
}
这篇关于Javascript:如何使用promise迭代数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!