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 forloop when the iteration count is huge. But it’s okay to useforEachfor more readable code.
This post is licensed under CC BY 4.0 by the author.