为什么向后迭代数组比向前迭代快

IT技术 javascript performance optimization
2021-03-06 02:55:55

鉴于此代码:

var arr = [];

for (var i = 0; i < 10000; ++i)
    arr.push(1);

远期

for (var i = 0; i < arr.length; ++i) {}

向后

for (var i = arr.length - 1; i >= 0; --i) {}

硬编码转发

for (var i = 0; i < 10000; ++i) {}

为什么向后的速度要快得多?

这是测试:http : //jsperf.com/array-iteration-direction

6个回答

因为您的转发条件length每次都必须接收数组属性,而另一个条件只需要检查“大于零”,这是一项非常快的任务。

当你的数组长度在循环过程中没有改变,并且你真的查看了 ns-perfomance 时,你可以使用

for (var i=0, l=arr.length; i<l; i++)

顺便说一句:而不是for (var i = arr.length; i > 0; --i)您可能使用for (var i = arr.length; i-- > 0; )which 真正从 n-1 到 0,而不是从 n 到 1 遍历您的数组。

是的,这就是我为优化功能所做的。请注意,如果数组是可变的(通常不是),这可能会跳过一两个资源。例如,如果您循环遍历循环本身正在添加或删除的元素,这将不起作用。
2021-04-17 02:55:55
快进到 2018 年。看起来现代版本的浏览器即使在每次迭代中访问 arr.length 也不会使循环变慢(你的转发案例)
2021-04-27 02:55:55
你甚至可以做 for(... ; i-- ;)
2021-04-28 02:55:55
afaik,i<l是与 不同的计算i>0,但是它们相当相等(比未缓存的长度快):jsperf.com/array-iteration-direction/3 - 但有些引擎确实识别并优化了其中的一些情况
2021-04-28 02:55:55
所以基本上这意味着如果我不更改数组并将 array.length 保留在变量中,那么向后速度 = 向前速度?示例: var length = array.length; for(var i = 0 ; i<length ; i++);
2021-05-02 02:55:55

因为在第一种形式中,您每次迭代都会访问一次length数组的属性arr,而在第二种形式中,您只访问一次。

好吧,你是对的......看起来它真的是一个混合的结果,但是缓存确实有帮助......谢谢XD
2021-04-29 02:55:55
@samccone - 你看到了什么结果(在哪个浏览器中进行哪个测试)?我看到缓存长度总是至少一样快,通常更快。
2021-05-17 02:55:55

如果您想让它们以相同的速度运行,则可以为前向迭代执行此操作;

for(var i=0, c=arr.length; i<c; i++){
}

因此,您的脚本不需要在每一步都占用数组的长度。

啊……有趣的是,你的方法现在获得了最快迭代的桂冠 jsperf.com/array-iteration-direction
2021-04-28 02:55:55

我对此并不完全确定,但这是我的猜测:

对于以下代码:

for (var i = 0; i < arr.length; ++i) {;
}

在运行时,每次循环通过后都会进行 arr.length 计算。这在单独使用时可能是微不足道的操作,但在涉及多个/大型阵列时可能会产生影响。您可以尝试以下操作:

 var numItems = arr.length;
    for(var i=0; i< numItems; ++i)
    {
    }

在上面的代码中,我们只计算一次数组长度,并使用计算出的数字进行操作,而不是一遍又一遍地执行长度计算。

再次,只是把我的想法放在这里。确实有趣的观察!

i > 0i < arr.length循环的每次迭代都快并且正在发生。

您可以通过以下方式减轻差异:

for (var i = 0, len = arr.length; i < len; ++i) {;
}

这仍然不如向后项目快,但比向前选项快。

看看硬编码测试jsperf.com/array-iteration-direction ......使用你的逻辑它应该更快不是吗?
2021-05-05 02:55:55