为什么在这个基准测试中while(i–)循环比for循环慢?
想象一个非常简单的任务,它需要一个紧密的循环,比如对数组的值求和。我编写了 5 种不同的代码来实现这一点:
const arr = Array(1000000).fill(0).map(() => Math.random());
// 1: (ab)using .forEach
let x1 = 0;
arr.forEach((i) => x1 += i);
// 2. using reduce
let x2 = arr.reduce((a, n) => a + n, 0);
// 3: classic forward for-loop
let x3 = 0;
for(let i = 0; i < arr.length; i++)
x3 += arr[i];
// 4: backward for-loop, should be faster, because comparison with a literal is faster
let x4 = 0;
for(let i = arr.length - 1; i >= 0; i--)
x4 += arr[i];
// 5: backward while-loop, should be fastest, because it combines comparison and decrement
let x5 = 0;
let i = arr.length;
while(i--)
x5 += arr[i];
我通常使用第一个或第二个版本,因为在大多数循环中,可读性比性能更重要。但是,为了好玩,我对此进行了基准测试。每次运行的结果略有不同,但在 Chrome 90.0.4430.95 上我看到了这个趋势:
- 版本 1 和 2 是最慢的,差距很大(预期)
- 版本 3、4 和 5 几乎同样快,但是
- 5 几乎从来都不是最快的(令人惊讶!)
- 大多数情况下,3 是最快的,与 4 相比略有差距(令人惊讶,但可能是由于测量不准确)
这是为什么?仅仅是基准不准确吗?那么为什么 5 几乎永远不会是最快的呢?我的浏览器是否优化了前向循环?
我想强调的是,这是一个纯粹的理论问题,在实际代码中,我并不关心这种微优化。
这里有一些我读过的参考问题:
JavaScript 循环性能 - 为什么将迭代器递减到 0 比递增更快- 从此我预计向后-for 比
向前-for 快。
Javascript 性能:While 与 For 循环- 从这里我预计 backward-while 比 backward-for 更快。
这两个问题都有些旧,因此由于更好的浏览器支持,它们可能已经过时了。