我尝试了两种不同的方式做某事,我对性能结果感到惊讶:
我有两个版本的函数:
使用for
:
$scope.hasBlockResult = function (IS, area, block) {
if (!block)
return false;
for (var i = 0; i < $scope.filteredCartoList.length; i++) {
if ($scope.filteredCartoList[i].informationSystem === IS
&& $scope.filteredCartoList[i].area === area
&& $scope.filteredCartoList[i].block === block)
return true;
}
return false;
};
并使用some()
函数:
$scope.hasBlockResult = function (IS, area, block) {
if (!block)
return false;
return ($scope.filteredCartoList.some(function (carto) {
if (carto.informationSystem === IS && carto.area === area && carto.block === block)
return true;
return false;
}));
};
同样的事情:
在for
:
for (var i = 0; i < $scope.filteredCartoList.length; i++) {
if ($scope.filteredCartoList[i].informationSystem == IS
&& $scope.filteredCartoList[i].type != 'AM'
&& $scope.filteredCartoList[i].type != 'IF'
&& $scope.filteredCartoList[i].area == area
&& $scope.filteredCartoList[i].block == block)
$scope.resultList.push($scope.filteredCartoList[i]);
}
和filter()
:
$scope.resultList = $scope.filteredCartoList.filter(function (carto) {
if (carto.informationSystem == IS
&& carto.type != 'AM'
&& carto.type != 'IF'
&& carto.area == area
&& carto.block == block)
return true;
return false;
});
我希望filter()
和some()
方法比for
方法更快,但在两种情况下,根据angularjs batarang性能标签,for
是更快。
答案 0 :(得分:6)
鉴于您在评论中发布的文章(以及相关的benchmarks),我们可以得出结论,您注意到的巨大差异是因为您所看到的基准是废话。
console.timeEnd
和console.log
,这两个都是非常低效的。some
示例执行类型协作。现在,通过300个项目和300次迭代的阵列,在Chrome 44上的8GB DDR3 Intel i5笔记本电脑上消除这些因素时的结果如下(按从最慢到最快的顺序重新排序):
OBJECT Average 0.0010666643114139636
SEEK Average 0.00593666957380871
LOOP Average 0.008436664550875625
SOME Average 0.013993332007279
FILTER Average 0.02592999837361276
这些是预期的,这就是为什么:
Seek实现为使用indexOf
定位元素,然后在直接数组索引处访问该元素。确定某些东西是否等于某个值的实际方法是由浏览器实现的,所以我不知道这个方法是如何工作的,但人们会认为它本质上是浏览器实现的优化版some
。
循环方法较慢主要是因为与'seek'测试不同,循环测试遍历整个数组并执行数组访问和对象访问。搜索方法不会这样做。它在找到元素后几乎立即爆发。我不知道这是否能解释搜索和循环之间的差异,尽管我不会感到惊讶。然而,再次,搜索是浏览器实现的,因此能够进行优化 - 循环可以优化,但你仍然必须抵消它可以优化少于搜索的事实。
有些人每次迭代都会调用函数调用的开销。此外,JIT编译器根本无法对此进行优化,因为JIT编译器不知道您要将哪些内容传递到some
。
Filter在返回之前迭代整个数组,所以这不应该是一个惊喜。
至少在Chrome中,对象访问速度极快,因为对象在类的引导下进行编译。值得一提的是所有数组都是对象,所以使用相同的方法。
TLDR这些基准测试非常没用,因为它们没有编程相同,几乎没有一个测试访问方法,但实际上正在测试字符串连接和console.log
速度等其他内容。数组中的300个项目也非常小,你需要一个更大的数组来获得任何确定的结果。
答案 1 :(得分:5)
在性能方面,没有什么比本机(vanilla)javascript更好的了。问题可以归结为&#34;你是想花时间和资源通过自己动手来重新发明轮子,还是只是利用为你做这件事的外部库?&#34;。是的,你牺牲了加载时间和性能,但节省时间和金钱。你可以通过缓存数组的长度来使你的for循环更快
for (var i = 0, len = $scope.filteredCartoList.length; i < len; i++)
这会更快,特别是在IE中工作,因为在这里缓存$scope.filteredCartoList
的长度,而不是在循环的每次迭代中计算它。
答案 2 :(得分:1)
考虑以下两个例子:
for (var i = 0; i < array.length; i++) {
doThing(array[i]);
}
VS
function processItem(item) {
doThing(item);
}
for (var i = 0; i < array.length; i++) {
processItem(array[i]);
}
这基本上是两者之间的差异。 filter
和some
内部也必须有一些逻辑来处理来自processItem
的返回值,但基本上你在循环上堆叠了一个额外的函数调用。