问题描述
这是一个简单的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,并在每次迭代时使用正索引访问同一数组。 因此它反向通过数组。
在我的PC上,第一个循环需要6秒钟以上的时间才能完成,但是第二个循环只需要400毫秒左右的时间。
为什么第二个循环比第一个循环快?
1楼
因为iterations[-1]
计算结果是undefined
(这很慢,因为它必须iterations[-1]
整个原型链,并且不能采用快速路径),所以用NaN
进行数学运算也总是很慢,因为这是不常见的情况。
同样,使用数字初始化iterations
将使整个测试更加有用。
专家提示:如果您尝试比较两个代码的性能,最后它们都应导致相同的操作...
关于性能测试的一些一般说法:
如今,性能是编译器的工作,通过编译器优化的代码将始终比您尝试通过“技巧”进行优化的代码更快。 因此,您应该编写编译器可能会优化的代码,即在每种情况下都是其他人编写的代码 (如果这样做,您的同事也会爱上您)。 从引擎的角度来看,优化是最有益的。 因此,我会写:
let acc = 0;
for(const value of array) acc += value;
// or
const acc = array.reduce((a, b) => a + b, 0);
但是最后, 这只是一个循环 ,如果循环执行不佳,您将不会浪费很多时间,但是如果整个算法执行不佳(时间复杂度为O(n?)或更高),您将浪费很多时间。 专注于重要的事情,而不是循环。
2楼
为了详细说明Jonas Wilms的答案,Javascript不适用于否定索引(与Python等语言不同)。
iterations[-1]
等于iteration["-1"]
,后者在数组对象中查找名为-1的属性。
这就是为什么iterations[-1]
将评估为undefined
。