Search code examples
javascriptangularjsperformance

Why using for is faster than some() or filter()


I tried two different way to do something and I am surprised by the performance result :

I have 2 versions of a function :

Using a 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;
};

And using some() function :

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

Same thing here :

Between the 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]);
    }

and the 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;
});

I expected the filter() and the some() methods to be faster than the for method, but in both case, according to angularjs batarang performance tab, the foris faster.


Solution

  • I took a look at the benchmarks you posted in the comments. These benchmarks have a few flaws:

    • The loop example uses console.timeEnd and console.log within the benchmark itself, which are both slow. None of the other examples did this at time of writing.
    • The some example performs type coercion.
    • All of the tests are performing string concatenation within their loops.

    In order to draw any conclusions from these benchmarks, we first need to eliminate these sources of bias.

    Here are the results on an 8GB DDR3 i5 Laptop with these biases eliminated, re-ordered in terms of fastest to slowest (lower numbers are better):

    OBJECT Average 0.0010666643114139636
    SEEK Average 0.00593666957380871
    LOOP Average 0.008436664550875625
    SOME Average 0.013993332007279
    FILTER Average 0.02592999837361276
    

    These are what is to be expected, and here is why:

    Object Access

    Object access is very quick because objects are essentially hash maps. Regardless of the size of the object, accessing an element will be a constant speed.

    Seek

    Seek is implemented as using indexOf to locate an element and then accessing that element at the direct array index. While the actual method of doing this is implementation-specific, it is going to be very similar to object access and thus very fast.

    Loop

    The loop approach is slower primarily because unlike the 'seek' test, the loop test iterates over the entire array and does both array access AND object access. The seek method doesn't do this. It breaks out almost immediately after finding the element.

    This means that in all except the worst cases, seek will be faster than loop.

    Some

    Some has the overhead of a function invocation to be invoked every single iteration. In addition, this cannot be optimized at all by the JIT compiler because the JIT compiler doesn't know what you're going to pass into some. Some will, at best, perform the same as loop in the most optimized cases but because of the function invocations it will always be slower.

    Filter

    Filter has all the caveats of "some", but it will always iterate over the entire array instead of halting at a single element. Due to this, you should always expect filter to be much slower than a for loop - especially when you consider that filter also creates a new array which it returns!