5

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.

Mike Cluck
  • 28,921
  • 12
  • 72
  • 85
Ellone
  • 3,022
  • 9
  • 33
  • 61
  • I would imagine the some and filter will have to loop through as well – Huangism Jul 16 '15 at 16:14
  • `filter()` should be as slow as `for`. `some()` will be, in worst case scenario, as slow as `for`. I am confused as to why you thought either of them should be faster than the native for given both of them use that under the hood. – Dan Jul 16 '15 at 16:14
  • @Dan Pantry : I thought it would be more optimized after reading this article : http://www.andygup.net/fastest-way-to-find-an-item-in-a-javascript-array/ – Ellone Jul 16 '15 at 16:16
  • 2
    `filter` iterates over the entire array, so that's out. `some` MIGHT be faster if it encounters the element matching the predicate early in the array but it can go right up to the length of the array as well if it doesn't find an element that matches the predicate. You are likely to see better performance increases by only iterating the array once (i.e, deferred execution) rather than trying to micro-optimize like this. – Dan Jul 16 '15 at 16:17
  • For what it's worth, that guys tests are dubious at best. He's performing a lot more work inside of the his loop test than in any of his other tests. – Mike Cluck Jul 16 '15 at 16:20
  • 3
    For one, he's doing console.log in his loop and no where else. Removing the console log and console timeEnd drops the loop time to `0.005800000002030477` (from `0.03269333333188721`). That's 7x faster. This ends up making 3x as fast as filter and similar in speed to some (although slower) on my machine. That's what I would expect to see. Object access and direct array access are both blazingly fast as would be expected, and some would be faster if the some was used earlier on in the array. Those tests are rubbish. – Dan Jul 16 '15 at 16:22
  • And also in each of his tests he does string concatenation, which again dumpsters the speed. – Dan Jul 16 '15 at 16:27
  • @Dan Pantry, in the case of `filter`, `for`also iterates the entire array. About `some`, why should it be different from `for` then ? They both iterates throught the array until they find a matching element, no ? – Ellone Jul 17 '15 at 08:29
  • @Ellone There are two things here - firstly, his `some` example is using `==` which performs type co-ercion and thus adds to the overhead. Eliminating this puts us at about a .003 second discrepancy. This can be explained by the fact that `some` has to invoke a function for every element in the array (`for` doesn't). In addition, the JIT compiler in your browser may optimize a `for` loop. It can't optimize `some`. – Dan Jul 17 '15 at 08:37

3 Answers3

17

I took a look at the benchmarksyou 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!

Dan
  • 9,064
  • 1
  • 29
  • 59
  • This answer doesn't really make sense, loop time is 3x faster than filter time and your explanation is 'loop iterates the whole array', ' filter iterates the whole array' ???? so why is it 3x slower? doesn't' answer the question at all – RenaissanceProgrammer Feb 09 '21 at 22:52
  • @RenaissanceProgrammer Parts of this answer are incorrect (I'll fix that now); the part about filter iterating "the entire" array is when comparing it to *some* - Filter is slower than some because some only needs to hit part of the array, but filter all of it, and some is slower than loop because of optimizations, but on the whole my point was that the benchmarking numbers *cannot be relied on* because they are biased. – Dan Feb 09 '21 at 23:58
  • I've updated the answer to simplify the language a bit, but the answer is (and was) accurate. – Dan Feb 10 '21 at 00:25
  • thanks for coming back to this, wasn't really expecting it. are you saying the timing numbers above in the box are biased? I thought they were your numbers on your particular machine. my comment was in reference to these numbers which show a ~3x difference - LOOP ~0.008, FILTER ~0.026 – RenaissanceProgrammer Feb 10 '21 at 04:12
  • The ones I have presented are accurate; the ones that OP was referring to are biased. – Dan Feb 10 '21 at 16:06
  • To be clear: I was saying that the benchmarks he was looking at are biased and should not be relied upon, even if their conclusions broadly paint the same picture when you remove the bias, as I did. – Dan Feb 10 '21 at 21:26
  • 1
    Right yeah that makes since, OP was led to believe loop is faster and it is but not based on their test data. – RenaissanceProgrammer Feb 11 '21 at 23:27
6

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.

ODelibalta
  • 1,772
  • 1
  • 14
  • 25
  • If you want to go nuts with performance, you should do the loop in reverse as well because comparison to zero is faster than comparison to anything else. `for (var i=$scope.filteredCartoList.length - 1; i >= 0; i--)` but we're talking microseconds here at this point – hobberwickey Mar 25 '21 at 08:04
3

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.

Mike Cluck
  • 28,921
  • 12
  • 72
  • 85
  • Yeah I thought functions such as `filter` or `some` might be something different than a `for` like using bit comparaison or more deep method. – Ellone Jul 17 '15 at 08:31