Javascript 为什么使用for比some()或filter()更快

Javascript 为什么使用for比some()或filter()更快,javascript,angularjs,performance,Javascript,Angularjs,Performance,我尝试了两种不同的方法来做某事,我对性能结果感到惊讶: 我有两个版本的函数: $scope.hasBlockResult = function (IS, area, block) { if (!block) return false; return ($scope.filteredCartoList.some(function (carto) { if (carto.informationSystem === IS && cart

我尝试了两种不同的方法来做某事,我对性能结果感到惊讶:

我有两个版本的函数:

$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;
    }));
};
对使用

$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;
};
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]);
    }
$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;
});
这里也一样:

之间:

$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;
};
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]);
    }
$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 performance tab,在这两种情况下,
for
的速度更快。

考虑以下两个例子:

for (var i = 0; i < array.length; i++) {
    doThing(array[i]);
}
for(变量i=0;i
vs

函数processItem(项目){
打点(项目);
}
对于(var i=0;i
这基本上就是两者的区别。
filter
some
中还必须有一些逻辑来处理来自
processItem
的返回值,但基本上,您是在循环的顶部堆积一个完整的额外函数调用。

在性能方面,没有什么比原生(普通)javascript更好的了。问题归结为“您是想花费时间和资源,通过自己动手来重新发明轮子,还是仅仅利用一个外部库来为您实现?”。是的,你牺牲了加载时间和性能,但你节省了时间,时间就是金钱。通过缓存数组的长度,可以加快for循环

for(变量i=0,len=$scope.filteredCartoList.length;i

这将更快地工作,尤其是在IE中,因为这里您正在缓存
$scope.filteredCartoList的长度,而不是在循环的每个迭代中计算它。

我查看了您在评论中发布的内容。这些基准有一些缺陷:

  • 循环示例在基准本身中使用
    console.timeEnd
    console.log
    ,这两种方法都很慢。在撰写本文时,其他例子都没有这样做
  • some
    示例执行类型强制
  • 所有测试都在其循环中执行字符串连接
为了从这些基准中得出任何结论,我们首先需要消除这些偏差来源

以下是8GB DDR3 i5笔记本电脑的结果,消除了这些偏差,按从最快到最慢的顺序重新排序(数字越小越好):

这些都是可以预期的,原因如下:

对象访问 对象访问非常快,因为对象本质上是散列映射。无论对象大小如何,访问元素的速度都是恒定的

寻找 Seek的实现方式是使用
indexOf
定位元素,然后在直接数组索引中访问该元素。虽然实际的方法是特定于实现的,但它将非常类似于对象访问,因此速度非常快

环 循环方法的速度较慢,主要是因为与“seek”测试不同,循环测试迭代整个数组,并执行数组访问和对象访问。seek方法不能做到这一点。它几乎在找到元素后立即爆发

这意味着除了最坏的情况外,在所有情况下,seek都比loop快

一些 有些具有每次迭代都要调用的函数调用的开销。此外,JIT编译器根本无法对其进行优化,因为JIT编译器不知道您将向
some
传递什么。在优化程度最高的情况下,有些函数最多只能执行与循环相同的操作,但由于函数调用的原因,执行速度总是较慢

滤器
过滤器具有“some”的所有警告,但它总是在整个数组中迭代,而不是在单个元素上停止。因此,您应该总是期望过滤器比for循环慢很多,特别是当您认为<代码>筛选器< /代码>也创建了一个新数组时,它返回了!p> 我想some和filter也必须循环通过
filter()
应该和
for
一样慢
some()
在最坏的情况下,速度将与
一样慢。我不明白为什么你认为它们中的任何一个都应该比本地的更快,因为它们都在引擎盖下使用。@Dan Pantry:读了这篇文章后,我认为它会更优化:
filter
迭代整个数组,所以就这样了
some
如果在数组的早期遇到与谓词匹配的元素,则速度可能会更快,但如果没有找到与谓词匹配的元素,则也可以直接到达数组的长度。通过只迭代一次数组(即延迟执行),而不是像这样尝试微优化,您可能会看到更好的性能提高。首先,他在循环中执行console.log,而不是在其他地方。删除控制台日志和控制台时间结束会将循环时间降至
0.005800000002030477
(从
0.032693333188721
)。这样快了7倍。这最终使3倍快的过滤器和类似的速度,一些(虽然较慢)在我的机器上。这就是我希望看到的。对象访问和直接阵列访问都像预期的那样快得惊人,如果在阵列中更早地使用了some,那么一些会更快。那些测试都是垃圾。是的,我认为像
filter
some
这样的函数可能与
for
不同,比如使用位比较或更深入的方法。这个答案没有意义,循环时间比过滤时间快3倍,你的解释是“循环迭代整个数组”,'过滤器迭代整个数组'????那么,为什么要慢3倍呢?一点也不回答这个问题all@RenaissanceProgrammer这个答案的一部分是不正确的(我现在就纠正它);过滤器迭代“整个”数组的部分是将其与some-Fil进行比较