6

Many of us probably already know this:

var list = ...
var index = list.length

while( index-- ) {
    // do something
}

It's supposedly the fastest way to do a loop in javascript since you avoid an extra test. So far, over the past years, I used this technique when dealing with data where speed was important and the order didn't really matter.

But now I stumbled upon an article that says this is actually slower when dealing with arrays.

Which makes you avoid an extra test (compared to the standard for loop). But you know what ? this will be much slower than using the right order. Because all CPU caches in the world expect the processing to be ‘straight’, you will have cache misses again and again, and a 2X slow down is what you’ll get when you are lucky.

So do not loop backward unless you have very good reasons to do so.

Source: https://gamealchemist.wordpress.com/2013/05/01/lets-get-those-javascript-arrays-to-work-fast/

Now I'm curious! I only have limited possibilities to test these things, and every other place I found still says that a backward loop is the fastest possible way (even multiple answers on stackoverflow). Is that really true when dealing with (possibly large) arrays?

And before the premature optimization answer pops up (like it often does with this type of question): This is mainly just curiosity and yes, in things like games, performance matters!

About jsperf: So far, jsperf seems to imply that the backward loop is faster (I can't check the tests right now since it doesn't load the result on any atm - so I'm recalling what I saw before). That's the source of this question: The two pieces of information are contradicting themselves - at least if that what's stated in that article is true! So what's "correct", in the end?

p u
  • 1,395
  • 1
  • 17
  • 30
Katai
  • 2,773
  • 3
  • 31
  • 45
  • 3
    Why don't you just test it in jsperf in the browsers you care about (takes a few minutes to get your first results)? ALL performance questions MUST be answered with testing in the environment you care about. Posting this question without any testing of your own seems to indicate that you just want someone else to do the testing for you. – jfriend00 Aug 08 '15 at 08:10
  • well fact related the cache miss is true. CPU expects array to be traversed in order. – Sushant Aug 08 '15 at 08:12
  • Also, since JS engines are regularly adding performance enhancements, it is entirely possible that some or many browsers have added optimizations for the typical array iteration `for` loop to speed it up. Something you read a few years ago, may not still hold true today. – jfriend00 Aug 08 '15 at 08:12
  • @jfriend00 Yes, but that's also the problem (and reason for this question): jsperf seems to imply that the backwards loop is faster (I've seen a couple of tests floating around here during the years). So jsperf actually contradicts this - but maybe that's also the case because those tests are too focused on one thing? I was really interested to hear if the argument "Because all CPU caches in the world expect the processing to be 'straight', you will have cache misses..." is grounded in reality - because if that's the case, backwards loops should theoretically be slower, right? – Katai Aug 08 '15 at 08:15
  • @jfriend00 sorry, you were quite fast - my previous comment was refering to your first comment, not your second - just FYI ;) – Katai Aug 08 '15 at 08:16
  • 1
    If you have current jsperf performance data in several browsers, then post it. The question really is meaningless without some performance data. There's zero useful discussion to be had until measurements are taken to know what the current state of affairs is. You don't figure out which thing is going to be faster by theorizing about things. You measure. You may try to explain a measurement by theorizing, but NOT the other way around. – jfriend00 Aug 08 '15 at 08:18
  • @jfriend00 I tried to find a few, but all jsperf tests (since over an hour) are always just displaying "Loading cumulative results data…" whitout ever finishing. Don't know if jsperf is just down or something? I can't access any results. If they work for you: https://jsperf.com/loops/33, http://jsperf.com/fastest-array-loops-in-javascript/15 – Katai Aug 08 '15 at 08:20
  • Because you're having trouble running someone jsperf tests, that's no excuse. This question is meaningless until measurements are done and reported on. Then, theory can be discussed as to why the measurements are what they are. FYI, I successfully ran the first jspref you have linked in Chrome and got results. The test labeled "Reverse for loop" was the fastest. I would not be surprised if different browsers had different results. – jfriend00 Aug 08 '15 at 08:22
  • @jfriend00 I've edited the question a few minutes ago, adding the point about jspref. This question is not meaningless, it's asked exactly because what the article is stating is not matching jspref results. Other questions here alreay give the (accepted) answer that a backwards loop is faster - I'll add them to my question as reference. This question **is** about the discrepancy of the two (three) sources. – Katai Aug 08 '15 at 08:25
  • jsperf working just fine for me. Must be something on your end. – jfriend00 Aug 08 '15 at 08:26
  • Seems to be true for me as well, http://jsperf.com/fastest-array-loops-in-javascript/497 – Samir Alajmovic Jan 23 '16 at 21:02
  • Possible duplicate: https://stackoverflow.com/questions/8689573/why-is-iterating-through-an-array-backwards-faster-than-forwards – Anas Abu Farraj Dec 19 '18 at 07:02

1 Answers1

0

The reasoning in that argument is invalid. CPU caches provide benefits on ordered memory accesses because they cache blocks of memory and if you are going through memory in order then you will hit the same block a few times in succession rather than having to load a block each time.

However, whether you are going forwards or backwards in such a linear progression makes no difference to whether this applies.

There can be a lot of different factors in play affecting relative performance of such alternatives (not least if an engine tries to optimise particular common patterns which can mean that those that seem to be doing more work than a rival are actually doing less). Such factors can also differ considerably across platforms.

But this particular reason for expecting forward access to beat backwards access does not pan out.

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
  • It seems to refer to [cache prefetching](https://en.wikipedia.org/wiki/Cache_prefetching) which tries to fetch the next cache block before a cache miss occurs. – Bergi Jan 29 '19 at 14:52
  • @Bergi I had thought that was bidirectional when not trying something more exotic still. After all, going up and down memory used for stacks is a particularly common pattern. – Jon Hanna Jan 29 '19 at 14:55
  • Yes, you'd need to have a pretty dumb predictor, I just wanted to mention that the reasoning isn't entirely invalid. I agree however totally with "*There can be a lot of different factors in play…*" – Bergi Jan 29 '19 at 14:57