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

时间:2015-07-16 16:09:45

标签: javascript angularjs performance

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

我有两个版本的函数:

使用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是更快。

3 个答案:

答案 0 :(得分:6)

鉴于您在评论中发布的文章(以及相关的benchmarks),我们可以得出结论,您注意到的巨大差异是因为您所看到的基准是废话。

  • 基准测试编程不相同。循环示例使用console.timeEndconsole.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]);
}

这基本上是两者之间的差异。 filtersome内部也必须有一些逻辑来处理来自processItem的返回值,但基本上你在循环上堆叠了一个额外的函数调用。