JavaScript: Loop Performance Benchmark
I wondered if array methods are slower than the traditional for loop.
JavaScript: Loop Performance Benchmark
I wondered which loop algorithm (for(let i = 0; i < arr.length; i++), (forEach), (for…of), (for…in), (Object.keys()), (Object.entries())) is the fastest.
So I created a benchmark.
1. PerformanceMeasurer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PerformanceMeasurer = void 0;
// Performance measurement utilities
class PerformanceMeasurer {
constructor() {
this.stats = {};
}
measure(name, fn, iterations = 1) {
if (!this.stats[name]) {
this.stats[name] = { times: [], total: 0, min: Infinity, max: 0 };
}
for (let i = 0; i < iterations; i++) {
const start = performance.now();
fn();
const end = performance.now();
const time = end - start;
this.stats[name].times.push(time);
this.stats[name].total += time;
this.stats[name].min = Math.min(this.stats[name].min, time);
this.stats[name].max = Math.max(this.stats[name].max, time);
}
}
getStats(name) {
return this.stats[name];
}
getAllStats() {
return this.stats;
}
calculateMedian(times) {
const sorted = [...times].sort((a, b) => a - b);
const mid = Math.floor(sorted.length / 2);
return sorted.length % 2 === 0
? (sorted[mid - 1] + sorted[mid]) / 2
: sorted[mid];
}
printSummary(title, iterations, dataSize) {
console.log(`\n=== ${title} ===`);
console.log(`Total iterations: ${iterations}`);
console.log(`Data size: ${dataSize}\n`);
const methods = Object.entries(this.stats).map(([name, data]) => ({
name,
data,
}));
methods.forEach((method, index) => {
const avg = method.data.total / method.data.times.length;
const median = this.calculateMedian(method.data.times);
console.log(`${index + 1}. ${method.name}`);
console.log(` Average: ${avg.toFixed(3)}ms`);
console.log(` Median: ${median.toFixed(3)}ms`);
console.log(` Min: ${method.data.min.toFixed(3)}ms`);
console.log(` Max: ${method.data.max.toFixed(3)}ms\n`);
});
}
clear() {
this.stats = {};
}
}
exports.PerformanceMeasurer = PerformanceMeasurer;
2. Performance Benchmark (Object)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const _00_test_1 = require("./00-test");
const obj = {};
for (let i = 0; i < 1000000; i++) {
obj[i.toString()] = i * 2;
}
const iterations = 10000;
const measurer = new _00_test_1.PerformanceMeasurer();
measurer.measure("for...of loop (object values)", () => {
for (const x of Object.values(obj)) {
let y = x;
y = y + 1;
}
});
measurer.measure("for...in loop (object keys)", () => {
for (const x in obj) {
let y = obj[x];
y = y + 1;
}
});
measurer.measure("Object.keys() + for loop", () => {
const keys = Object.keys(obj);
for (let i = 0; i < keys.length; i++) {
let y = obj[keys[i]];
y = y + 1;
}
});
measurer.measure("Object.entries()", () => {
for (const [key, value] of Object.entries(obj)) {
let y = value;
y = y + 1;
}
});
measurer.printSummary(
"Object Loop Performance Statistics",
iterations,
Object.keys(obj).length
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
=== Object Loop Performance Statistics ===
Total iterations: 10000
Data size: 1000000
1. for...of loop (object values)
Average: 13.401ms
Median: 13.401ms
Min: 13.401ms
Max: 13.401ms
2. for...in loop (object keys)
Average: 46.187ms
Median: 46.187ms
Min: 46.187ms
Max: 46.187ms
3. Object.keys() + for loop
Average: 66.711ms
Median: 66.711ms
Min: 66.711ms
Max: 66.711ms
4. Object.entries()
Average: 198.382ms
Median: 198.382ms
Min: 198.382ms
Max: 198.382ms
If you only want to use values, use
Object.values()
, it’s the fastest. If you want to use both keys and values, usefor...in
, it’s the fastest.
3. Performance Benchmark (Array)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PerformanceMeasurer = void 0;
const _00_test_1 = require("./00-test");
Object.defineProperty(exports, "PerformanceMeasurer", {
enumerable: true,
get: function () {
return _00_test_1.PerformanceMeasurer;
},
});
const arr = Array.from({ length: 1000000 }, (_, i) => i * 2);
const measurer = new _00_test_1.PerformanceMeasurer();
const iterations = 10000;
measurer.measure(
"for...of",
() => {
for (const x of arr) {
const y = x;
}
},
iterations
);
measurer.measure(
"traditional for",
() => {
for (let j = 0; j < arr.length; j++) {
const x = arr[j];
}
},
iterations
);
measurer.measure(
"forEach",
() => {
arr.forEach((x) => {
const y = x;
});
},
iterations
);
measurer.printSummary(
"Array Loop Performance Statistics",
iterations,
arr.length
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
=== Array Loop Performance Statistics ===
Total iterations: 10000
Data size: 1000000
1. for...of
Average: 0.590ms
Median: 0.285ms
Min: 0.285ms
Max: 8.291ms
2. traditional for
Average: 0.312ms
Median: 0.286ms
Min: 0.285ms
Max: 1.286ms
3. forEach
Average: 1.562ms
Median: 0.286ms
Min: 0.285ms
Max: 11.081ms
I recommend using the
traditional for
loop when the iteration count is huge. But it’s okay to useforEach
for more readable code.
This post is licensed under CC BY 4.0 by the author.