1

In my quest to optimize my game engine I have discovered optimization i have been doing affecting each browser differently, in a lot of cases making one browser worse and the other better!

Currently I'm trying to optimize looping as i do alot of it and depending on the way this is done can have a big effect on the performance of my engine.

Based on the results here http://jsperf.com/for-vs-while-loop-iterating/3

It seems a reverse for loop in chrome is the fastest

var l = foo.length;
for (var i = l; i--;) {

}

And in firefox a forward for loop is fastest

var l = foo.length;
for (var i = 0; i < l; i++) {

}

Now in order to use the correct one per browser I'm doing something like this

function foreach(func, iterations){
    var browser = $.browser;

    var i;

    if (browser.webkit)
    {
        for(i=iterations;i--;)
        {
            func(i);
        }
    }
    else
    {
        for (i = 0; i < iterations; i++)
        {
            func(i);
        }
    }
}

but it seems there may be alot of overhead here that may hurt performance.

If you were to provide different ways of looping for different browsers what would you do?

EDIT: seems there was a bug in my testing where i was doing one too many loops on the forward loop and now chrome seems to be the fastest there also, I may not need to optimize the loops but it may still be worth while as mention in another comment incase browser versions change performance again

3
  • In the second example, you meant i < l, not i <= l which would loop an extra time.. Commented Aug 14, 2011 at 14:04
  • “I have discovered optimization i have been doing affecting each browser differently, in a lot of cases making one browser worse and the other better!” — Yup! Welcome to the web. Commented Aug 14, 2011 at 14:07
  • Ha yeah I have never really had to deal with such a hig performance web application yet, had plenty of fights with the dom and css in different browsers but optimization techniques as well? geez! Commented Aug 14, 2011 at 14:08

4 Answers 4

4

Unfortunately, if your goal is the best performance loop on each browser, the very last thing you want to do is introduce function calls into it. There's no way you can define your foreach function such that it will be anything like as fast as the straight for loop. Calling the iteration function will wash out any gains you might get.

A quick jsperf can confirm this easily enough. For instance, run this one on Chrome or a recent version of Firefox or Opera. It compares looping forward with for, backward with for, or using the browser's built-in Array#forEach function (part of ECMAScript5). (I think we can assume any foreach function you build will be slower than the built-in one.) As you can see, the forEach version is dramatically slower than either of the for loops, which makes sense: Calling functions isn't very expensive, but it isn't free.

Mind you, what you're doing in the loop probably washes out the difference between counting up and count down. What I'd do is figure out what's fastest on the slower browsers, and use that. You said, for instance, that a reverse loop is faster in Chrome but a forward loop is faster in Firefox. As Chrome's V8 is dramatically faster than Firefox's SpiderMonkey (at the moment, these things are constantly in flux), pick the forward loop, as it's faster on the slower engine.

Otherwise, you're into needing to do preprocessing on your code and churning out a different version tailored to each browser.

Sign up to request clarification or add additional context in comments.

4 Comments

There is something a little flawed with your forEach test case, your using an anonymous function and it will be significantly slower in some browser than having a declared function. You can see this test I did for the different : jsperf.com/conditionnal-loop. Nonetheless, I'm still 100% with you on this one. What will make a difference is the code inside the loop.
@HoLyVieR: There's no difference in the speed of creating a function depending on whether it's named or not. Where you might notice a speed difference is in code that needlessly re-creates the function over and over again, which is naturally slower. People frequently do that with anonymous functions, because people tend to use anonymous function expressions but named function declarations (for good reason, various implementations, particularly IE, have bugs related to named function expressions). I added a declared, named function test case to the page anyway, just for kicks.
@TJ What I was pointing out was more about the function reuse, than naming the function. If your re-using the same function it's not going to be as slow as when you create a new one each time. It probably just wasn't worded correctly in my first comment.
@HoLyVieR: But even in my first copy, I was reusing the same function for the entire loop. When you do a.forEach(function(val) { ... }); one function is created and passed into forEach, which then calls it repeatedly.
2

I don't think your overhad is as big as you feel, but what you can do is do your test only once:

var foreach;
if (forwardIsFaster) {
    foreach = function (func, iterations) {
        // loop forwards...
    };
} else {
    foreach = function (func, iterations) {
        // loop backwards...
    };
}

That said, I'm not sure using browser sniffing is the best solution here; maybe instead do a test loop on startup, measure which solution is faster, and choose the one that turns out to be faster.

6 Comments

what issues are there with testing by browser? I kinda like the idea of testing for fastest loop then using that, just wondering whats wrong with the browser test?
You never know if the next Chrome version optimizes loops differently, or if the performance is different on, say, a Mac or a 64 bit system, etc. All you have is "At this point in time, on some machines, it's this way."
I would imagine that most of the time in a situation like this will not be spent on the looping construct but on the func that is being called in each iteration. The function call overhead may end up being more significant.
"I don't think your overhad is as big as you feel..." Yes, it is. It will completely and utterly wash out any difference between counting up or counting down, thanks to the function calls.
@T.J.Crowder: The OP is talking about the performance of the browser check -- you're certainly not suggesting that a simple if (browser.webkit) is a performance hog?
|
2

When you start doing something significant inside the loop (e.g. just printing the variable), the order of iteration doesn't matter, see:

http://jsperf.com/for-vs-while-loop-iterating/4

So stop caring about this and if (and only if) your code is slow in any place, just profile it and optimize that part.

Comments

1

You could make foreach return a function, which would be an iterator. So you would have, once in your script, var iterator = foreach($.browser.webkit);. From then on, you would just use iterator(iterations, callback), which would no longer be executing any conditionals.

The key, basically, is that the user's browser won't change, so the result of the execution of that conditional needs to be evaluated only once per script.

1 Comment

Any solution involving a function call per element will be dramatically slower than just picking a direction and living with the fact it's slower on one browser than another.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.