【问题标题】:Why is iterating through an array backwards faster than forwards为什么向后迭代数组比向前迭代更快
【发布时间】:2012-01-31 03:40:30
【问题描述】:

鉴于此代码:

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

【问题讨论】:

标签: javascript performance optimization


【解决方案1】:

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

【讨论】:

  • @samccone - 您看到了什么结果(在哪个浏览器中进行了哪个测试)?我看到缓存长度总是至少一样快,而且通常更快。
  • 好吧,你是对的......看起来它确实是一个混合的结果,但缓存确实有帮助......谢谢XD
【解决方案2】:

i &gt; 0i &lt; arr.length 快,并且在循环的每次迭代中都会发生。

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

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

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

【讨论】:

【解决方案3】:

如果你想让它们保持相同的速度,你可以这样做进行前向迭代;

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

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

【讨论】:

【解决方案4】:

这些同样好:

var arr= [], L= 10000;
while(L>-1) arr[L]= L--;

var arr= [], i= 0;
while(i<10001) arr[i]=i++;

【讨论】:

  • 应该是while(--L&gt;=0) arr[L] = L;
【解决方案5】:

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

对于以下代码:

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

在运行期间,每次循环通过后都会进行 arr.length 计算。当它独立时,这可能是一个微不足道的操作,但在涉及多个/巨大的数组时可能会产生影响。您可以尝试以下方法吗:

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

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

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

【讨论】:

    【解决方案6】:

    像下面那样做,它会以同样的方式执行。因为arr.length 在向前的每次迭代中都需要时间。

    int len = arr.length;
    

    前进

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

    向后

    for (var i = len; i > 0; --i) {
    }
    

    【讨论】:

    • 后面的情况是不对的。我所做的是for(i=len; --i&gt;=0;){
    • for (let i = arr.length; i-- &gt; 0;) {
    【解决方案7】:

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

    当你的数组长度在循环期间没有改变,并且你真的看 ns-perfomance 时,你可以使用

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

    顺便说一句:您可以使用for (var i = arr.length; i-- &gt; 0; ) 而不是for (var i = arr.length; i &gt; 0; --i),它实际上是从n-1 到0,而不是从n 到1。

    【讨论】:

    • 是的,这就是我优化功能的方式。请注意,如果数组是可变的(通常不是),这可能会跳过一两个资源。例如,如果您正在循环遍历循环本身正在添加或删除的元素,这将不起作用。
    • 你甚至可以做for(... ; i-- ;)
    • 所以基本上这意味着如果我不更改数组并将array.length保存在一个变量中,那么向后速度=向前速度?示例: var length = array.length; for(var i = 0 ; i
    • afaik,i&lt;l 是与 i&gt;0 不同的计算,但是它们相当相等(比未缓存的长度更快):jsperf.com/array-iteration-direction/3 - 但有些引擎确实识别并优化了其中一些案例
    • 快进到 2018 年。看起来现代版本的浏览器不会使循环变慢,即使在每次迭代中访问 arr.length 时(您的转发案例)
    猜你喜欢
    • 2023-04-06
    • 1970-01-01
    • 1970-01-01
    • 2012-11-17
    • 1970-01-01
    • 1970-01-01
    • 2018-11-17
    • 2022-11-22
    • 2012-11-14
    相关资源
    最近更新 更多