史蒂夫·桑德斯(Steve Sounders)在他的书Even Faster Web Sites中写道,提高循环性能的一种简单方法是将迭代器递减为0,而不是增加总长度(实际上,该章由Nicholas C. Zakas撰写)。根据每次迭代的复杂程度,此更改可以节省多达50%的原始执行时间。例如:

var values = [1,2,3,4,5];
var length = values.length;

for (var i=length; i--;) {
   process(values[i]);
}

对于for循环,do-while循环和while循环,这几乎是相同的。

我想知道,这是什么原因? 为什么将迭代器递减得这么快? (我对这种技术的背景感兴趣,而不对证明这一主张的基准感兴趣。)

编辑:乍一看,这里使用的循环语法看起来是错误的。没有length-1i>=0,所以让我们澄清一下(我也很困惑)。

这是常规的for循环语法:
for ([initial-expression]; [condition]; [final-expression])
   statement
  • 初始表达式-var i=length
    首先评估此变量声明。
  • 条件-i--
    该表达式在每次循环迭代之前进行求值。它将在第一个通过循环之前递减变量。如果此表达式的计算结果为false,则循环结束。在JavaScript中,0 == falsei,因此,如果0最终等于false,它将被解释为0 == false,并且循环结束。
  • 最终表达式

    该表达式在每次循环迭代结束时进行评估(在下一次条件评估之前)。这里不需要它,它是空的。这三个表达式在for循环中都是可选的。

  • for循环语法不是问题的一部分,但是因为有点不常见,所以我认为对其进行澄清很有趣。也许它之所以更快的一个原因是,因为它使用了更少的表达式(ojit_code“trick”)。

    最佳答案

    我不确定Javascript,在现代编译器中,这可能并不重要,但是在“旧时代”中,此代码:

    for (i = 0; i < n; i++){
      .. body..
    }
    

    会产生
    move register, 0
    L1:
    compare register, n
    jump-if-greater-or-equal L2
    -- body ..
    increment register
    jump L1
    L2:
    

    而向后计数的代码
    for (i = n; --i>=0;){
      .. body ..
    }
    

    会产生
    move register, n
    L1:
    decrement-and-jump-if-negative register, L2
    .. body ..
    jump L1
    L2:
    

    因此在循环中,它仅执行两个额外的指令,而不是四个。

    关于JavaScript循环性能-为什么将迭代器减0的速度比增加迭代的速度快,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30159842/

    10-14 12:52
    查看更多