首页 > 解决方案 > 为什么负数组索引比正数组索引慢得多?

问题描述

这是一个简单的 JavaScript 性能测试:

const iterations = new Array(10 ** 7);

var x = 0;
var i = iterations.length + 1;
console.time('negative');
while (--i) {
	x += iterations[-i];
}
console.timeEnd('negative');

var y = 0;
var j = iterations.length;
console.time('positive');
while (j--) {
	y += iterations[j];
}
console.timeEnd('positive');

第一个循环从 10,000,000 计数到 1,并在每次迭代中使用负索引访问长度为 1000 万的数组。所以它从头到尾遍历数组。

第二个循环从 9,999,999 计数到 0,并在每次迭代中使用正索引访问同一个数组。所以它反向通过数组。

在我的电脑上,第一个循环需要超过 6 秒才能完成,但第二个循环只需要约 400 毫秒。

为什么第二个循环比第一个快?

标签: javascriptarrays

解决方案


因为iterations[-1]将评估为undefined(这很慢,因为它必须沿着整个原型链上升并且不能走一条快速的路径)而且用它做数学NaN总是很慢,因为它是不常见的情况。

同样用数字初始化iterations将使整个测试更有用。

专业提示:如果您尝试比较两个代码的性能,它们最终都应该导致相同的操作......


关于性能测试的一些通用词:

这些天,性能是编译器的工作,编译器优化的代码总是比你试图通过一些“技巧”优化的代码快。因此,您应该编写可能由编译器优化的代码,并且在任何情况下,都是其他人编写的代码(如果您这样做,您的同事也会喜欢您)。从引擎的角度来看,优化这一点是最有益的。因此我会写:

 let acc = 0;
 for(const value of array) acc += value;

 // or
 const acc = array.reduce((a, b) => a + b, 0);

但是最后它只是一个循环,如果循环执行不好,你不会浪费太多时间,但是如果整个算法执行不好(时间复杂度为 O(n²) 或更多),你会浪费很多时间。专注于重要的事情,而不是循环。


推荐阅读