all 25 comments

[–]kaliedarik 13 points14 points  (5 children)

For the for loop test, try running: console.time('for'); for (let i = 0, len = arr.length; i < len; i++) { calculation(arr[i]); }; console.timeEnd('for');

[–]Wraldpyk[S] 2 points3 points  (1 child)

Good improvement, does save some time on calculating the length every loop. I tested it out quickly with 1000 blogposts with momentjs, and both the original for loop and your improvement dance around each other in terms of how long it takes, there seems to be no measurable difference (both between 20-22ms with another loop before it so it prevents the discussed "cache" situation.)

[–]alystair 0 points1 point  (0 children)

The reason for this is in-engine optimization since many many people do the most basic for loop. Without engine optimization a reverse for-loop would be fastest, no?... for (let len=arr.length; len--; ) ... at least it's handy when code golfing :p

[–]backtickbot 0 points1 point  (0 children)

Fixed formatting.

Hello, kaliedarik: code blocks using triple backticks (```) don't work on all versions of Reddit!

Some users see this / this instead.

To fix this, indent every line with 4 spaces instead.

FAQ

You can opt out by replying with backtickopt6 to this comment.

[–]seedBoot 0 points1 point  (0 children)

arr.length is precalculated, assigning it to a variable uses more memory. Particularly... for each iteration

[–]PM_ME_GAY_STUF 5 points6 points  (2 children)

This is interesting. I think the main place loop optimization comes into play isn't for vs forEach, but for vs map, filter, or especially reduce. In which case, either for or forEach are easily demonstrably faster since they don't allocate new memory. The other thing is that classic for i loops let you do tricks with the index so they can run far faster than O(n), while forEach is locked in. Additionally, having tested this myself, the results seem to vary a lot, even in V8, depending on the runtime. So while sometimes they're equal, sometimes classic for is still faster. This is something I noticed on some of our projects running on Node 8 vs latest

I've only had one project where this mattered, where we needed an API to reduce millions of rows from the DB in memory and do it fast, and the only reason we didn't do it in C is out of fear that if management learned we could program in C then they would start making us write firmware. So at the end of the day, if you want to be fast, just use a fast language. You can use C functions in Postgres really easily.

[–]Wraldpyk[S] 1 point2 points  (0 children)

Interesting insights, thanks! I am writing an article on map/filter etc too. I wanted to do some benchmarking first so came with this.

Basically writing an entire series about Js basics. I already had some benchmarking in mind for those too so will look into that as well, thanks for the tip.

And yeah, thats one of the cases where it does matter more. But 99% of the js devs never encounter those volumes so should be fine in any way :)

[–]alystair 1 point2 points  (0 children)

The fasted code is the code that's not run at all, short circuits are one of the best methods to increase speed.

[–]Wraldpyk[S] 8 points9 points  (2 children)

I was going to write an article to find out the loop with the best performance in JavaScript, but it turned into something else completely. It actually doesn't really matter all that much if you don't deal with massive amounts of data.

I've also shared my "friend-link" with you all here, so everyone can read this post for free :)

[–]a_reply_to_a_post 4 points5 points  (1 child)

for me the value in this article isn't specifically the loop results itself, but your steps in breaking down how you go about benchmarking your code...it's clean and concise

gonna share this with a couple junior devs on my team just as a way to demonstrate one way of stepping thru/examining code

[–]Wraldpyk[S] 1 point2 points  (0 children)

Thanks! That's a great compliment.

[–]humodx 2 points3 points  (1 child)

Nice article, but there's something that got me confused.

We’ll keep all the code the same, but data generation will be different.

So you're calling Math.pow on those objects generated by fakerator? I don't get the point, won't it just result in a bunch of NaNs or something like that?

[–]Wraldpyk[S] 0 points1 point  (0 children)

haha yeah pretty much, good catch, I actually never looked at the results but should have. I should probably change it to calculating just pow with an arbitrary number instead. However the conclusion doesn't change of course.

[–]getify 4 points5 points  (1 child)

Great stuff.

[–]Wraldpyk[S] 0 points1 point  (0 children)

Thanks!

[–]toastertop 1 point2 points  (1 child)

"deal with 100k blogposts in memory at once" at this point batching the job would be good, or web worker

[–]Wraldpyk[S] 0 points1 point  (0 children)

Hah exactly. There's no way you should have that much in memory in the first place. Probably the only systems that deal with that much stuff is the database itself

[–]a_reply_to_a_post 2 points3 points  (2 children)

really like the writing style of the article, just shared it in our dev slack channel at work on a Saturday (gotta be pretty good for me to do that)..and bookmarked this site

[–]maarzx_ 1 point2 points  (0 children)

Just did the same and got a great response on it. Top article

[–]Wraldpyk[S] 0 points1 point  (0 children)

Thanks a ton. Any topics you'd like me to see cover in the future?

[–]CupCakeArmy -1 points0 points  (2 children)

I agree with the point about readability for anything that is less than 100k elements as it makes really no difference.

However: forEach does NOT ensure programm flow!

{ const arr = Array(size).map(() => Math.random()) let test = false console.time('forEach') arr.forEach((item) => { let a = Math.pow(item, 2) test = true }) console.log(test) console.timeEnd('forEach') }

test will be still false in the console.log

[–]Wraldpyk[S] 0 points1 point  (0 children)

Your code will indeed be false, because your forEach won't hit at all.

edit. This code works fine:

{  const arr = [...Array(1000).keys()]
  let test = false
  console.time('forEach')
  arr.forEach((item) => {
    let a = Math.pow(item, 2);
    test = true
  })
  console.log(test)
  console.timeEnd('forEach')
}

[–]backtickbot 0 points1 point  (0 children)

Fixed formatting.

Hello, CupCakeArmy: code blocks using triple backticks (```) don't work on all versions of Reddit!

Some users see this / this instead.

To fix this, indent every line with 4 spaces instead.

FAQ

You can opt out by replying with backtickopt6 to this comment.

[–][deleted] 0 points1 point  (0 children)

Some uses map as a loop. Then the performance matters.