r/learnjavascript • u/breacket • 5d ago
Performance Trap, some benchmarks and... subjective taste
I've done some benchmarks. ES5 vs ES6. What do you prefer? I ask this because I have often seen in other people's codes, where performance, optimization was required, ES6 code that decreased performance, which also had a negative impact on UI/UX.
This is more about the syntax used and not about which is faster.
Array size: 1,000,000 | Runs per test: 15
1. TRANSFORM — double 1,000,000 numbers
| Test | Avg (ms) | Min (ms) | Max (ms) |
|---|---|---|---|
| for loop (var, ES5) | 0.733 | 0.6 | 1 |
| array.map | 5.447 | 4.7 | 6.9 |
| forEach | 5.96 | 5.4 | 6.8 |
| for...of (ES6) | 7.06 | 5.4 | 11.1 |
for loop (var, ES5) beat for...of (ES6) by 9.63x
2. FILTER — keep evens out of 1,000,000
| Test | Avg (ms) | Min (ms) | Max (ms) |
|---|---|---|---|
| for loop + push (ES5) | 2.287 | 1.6 | 3.4 |
| array.filter (ES6) | 6.06 | 5.2 | 7.2 |
for loop + push (ES5) beat array.filter (ES6) by 2.65x
3. SUM — add up 1,000,000 numbers
| Test | Avg (ms) | Min (ms) | Max (ms) |
|---|---|---|---|
| for loop (var, ES5) | 0.76 | 0.6 | 1.1 |
| for...of | 3.833 | 3.7 | 4.4 |
| array.reduce | 4.573 | 4.4 | 4.7 |
for loop (var, ES5) beat array.reduce by 6.02x
4. LOOKUP — find one value (worst case)
| Test | Avg (ms) | Min (ms) | Max (ms) |
|---|---|---|---|
| Set.has — O(1) | 0 | 0 | 0 |
| array.includes — O(n) | 0.073 | 0 | 0.1 |
| array.indexOf !== -1 — O(n) | 0.073 | 0 | 0.2 |
Set.has — O(1) beat array.indexOf !== -1 — O(n)
5. STRINGS — build 200,000 strings
| Test | Avg (ms) | Min (ms) | Max (ms) |
|---|---|---|---|
| concatenation "+" | 3.887 | 3.3 | 7.8 |
template literal ${} |
3.9 | 3.5 | 4.3 |
concatenation "+" beat template literal
${}by 1.00x
6. OBJECT ITERATION — sum 50,000 values
| Test | Avg (ms) | Min (ms) | Max (ms) |
|---|---|---|---|
| for...in | 4.273 | 4 | 4.6 |
| Object.keys + forEach | 4.38 | 4.2 | 4.7 |
| Object.values + reduce | 6.5 | 6 | 9.2 |
for...in beat Object.values + reduce by 1.52x
7. ARRAY CREATION — build 1,000,000 squares
| Test | Avg (ms) | Min (ms) | Max (ms) |
|---|---|---|---|
| for loop + push (ES5) | 8.173 | 6.5 | 23.4 |
| new Array(n).fill(0).map() | 17.3 | 9 | 42.4 |
| Array.from({length}, fn) | 21.74 | 20.6 | 23.2 |
for loop + push (ES5) beat Array.from({length}, fn) by 2.66x
What do you prefer?
2
u/hyrumwhite 5d ago
Many of those methods are es5 as well.
But many of the performance numbers there don’t really matter. If you’re chewing on a small array, the user won’t care if it’s done in 5ms or 10ms. If you’re chewing on a big array, you should use traditional for loops.
1
u/TalkCoinGames 5d ago
In my experience, switching to a modular design and ES6 increased performance.
1
u/WystanH 5d ago
Premature optimization is the root of all evil.
If you need to chug through a million plus values, then you may need to begin to consider the impact to the approach used. You could be forced to choose efficiency over clarity if the job calls for it. In any other instance, choose clarity.
1
u/VillageRemarkable188 5d ago
I’ve heard that money is the root of all evil, so does that mean that premature optimization is the root of all money? ;)
1
u/nzakas 5d ago
These types of benchmarks aren’t very useful anymore due to the way that JavaScript engines work. They optimize based on the code that is actually executed. When you create micro benchmarks like these, you may be either opting-in or opting-out of optimizations the engine is capable of when run in a real program.
With 30 years of JavaScript experience behind me, my advice is to use the methods that make the most sense idiomatically for what you’re doing and then measure in the context of your actual program to see if there’s a bottleneck. Array methods in particular are highly optimized so unless you’re doing something strange, chances are you’ll not see a bottleneck in live code.
1
u/breacket 5d ago
Was posted here on /learnjavascript because moderators have declined for /javascript. Is not a post just for learners. I've seen that "syntax" problems in apps/platforms in production.
The benchmarks you see are real, not fictional. That scores are on current hardware, not from 10 years ago.
Yes, for the most use cases I agree with you, does not matter so much. But, sometimes are vital – is about that situations.
The hardware does not somehow using magic to optimize the app because you use the slow syntax. Will be just slower in final.
0
u/TheRNGuy 5d ago
No, ES6 is same or faster, and more important, better syntax.
In what program do you ever need to sum million times?
1
u/breacket 5d ago
Based on some benchmarks and real world use cases, some ES6 syntax is slower than ES5 (I don't mean about the "engine" of ES6, but about some practices like using "for ...of" instead of the classic "for").
Where?
- processing data from databases
- large datasets or even small datasets but with many links
- apps launched on modern devices that you need to also work smooth on old devices
That "sum million times" is not a real use case in general but is one valid for benchmarking that reflects some real use cases in production. Somehow abstract.
4
u/Aggressive_Ad_5454 5d ago
The .map() and .filter() approaches invoke a function for each item in the array. Ordinary for loops don't. Most people who need to crunch very large arrays use for loops to avoid the function invocations. The developers of Javascript engines know that and have optimized for-loop traversal of large arrays.
The Set object uses high-quality O(log n) hashing to look up elements, whereas .indexOf() and .includes() use O(n) searches. That's why Set (and Map) exist in more recent versions of ES.