Ellone
Ellone

Reputation: 3898

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.

Upvotes: 13

Views: 43841

Answers (3)

Dan
Dan

Reputation: 10548

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!

Upvotes: 33

ODelibalta
ODelibalta

Reputation: 2254

Nothing beats native (vanilla) javascript when it comes to performance. Question boils down to "Do you want to spend time and resources in re-inventing the wheel by doing it yourself or just leveraging an external lib that does it for you?". Yes you sacrifice load time and performance but you save time and time is money. You can make your for loop faster by also caching the length of the array as such

for (var i = 0, len = $scope.filteredCartoList.length; i < len; i++)

This is going to work faster especially in IE because here you are caching the length of your $scope.filteredCartoList instead of calculating it every iteration of the loop.

Upvotes: 9

Mike Cluck
Mike Cluck

Reputation: 32521

Consider these two examples:

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

This is basically the difference between the two. There also has to be some logic inside of filter and some for handling the return value from processItem but basically you're stacking a whole extra function call on top of your loop.

Upvotes: 3

Related Questions