Arlen Beiler
Arlen Beiler

Reputation: 15906

forEach function much faster than equivalent for loop

In an Angular app I am building, I have two pieces of code which fire on every refresh. They both do the same thing, but the faster one is the array forEach function, which I thought was supposed to be slightly slower.

If you spot an error, great! But why would the foreach loop be so much faster. They come right after each other, and if I switch the order around, it doesn't make a difference.

First the faster one. This averages about 5 ms using performance.now().

var start = performance.now();
start = performance.now();
$scope.config.formTables.forEach(function (e, i, a) {
    ['tbody', 'thead', 'tfoot'].forEach(function (f, j) {
        if (!$scope.config[e][f]) return;
        $scope.config[e][f].forEach(function (g, k) {
            if(isFunction(g.calculated || {})) g.calculated.apply(g);
        })
    })
});
console.log(performance.now() - start);  

And now the slower one, which I thought should have been faster. This one takes 100-200 ms.

start = performance.now();
var i,j,k,e,f,g;
for(i = 0; i < $scope.config.formTables.length; i++){
    e = $scope.config[$scope.config.formTables[i]];
    if(e.thead)
    for(j = 0; j < e.thead.length; j++){
        f = e.thead;
        for(k = 0; k < f.length; k++){
            //g = f[j];
            if(isFunction(f[j].calculated || {})) f[j].calculated.apply(f[j]);
        }
    }
    if(e.tfoot)
    for(j = 0; j < e.tfoot.length; j++){
        f = e.tfoot;
        for(k = 0; k < f.length; k++){
            //g = f[j];
            if(isFunction(f[j].calculated || {})) f[j].calculated.apply(f[j]);
        }
    }
    if(e.tbody)
    for(j = 0; j < e.tbody.length; j++){
        f = e.tbody;
        for(k = 0; k < f.length; k++){
            //g = f[j];
            if(isFunction(f[j].calculated || {})) f[j].calculated.apply(f[j]);
        }
    }
}
console.log(performance.now() - start);

Upvotes: 0

Views: 148

Answers (1)

Bergi
Bergi

Reputation: 665456

No, they are not equivalent, because of this bit:

for(j = 0; j < e.thead.length; j++){
    f = e.thead;
    for(k = 0; k < f.length; k++){
        //g = f[j];
        if(isFunction(f[j].calculated || {})) f[j].calculated.apply(f[j]);
    }
}

Here you're basically iterating the same thing twice, nested which kills performance. Just omit that one of the loops - you also may notice that you're never using k in the loop body.

It should be just

if(e.thead) {
    f = e.thead;
    for(k = 0; k < f.length; k++){
        //g = f[j];
        if(isFunction(f[k].calculated || {})) f[k].calculated.apply(f[k]);
    }
}

Notice that f == "thead" and that j is never used in your forEach version.

You really should use more descriptive variable names, then things such as this would would be far more obvious. e and f are not synonymous in the two versions either.

Upvotes: 1

Related Questions