djd*_*d87 259 javascript optimization loops for-loop while-loop
我听过很多次了.向后计数时JavaScript循环真的更快吗?如果是这样,为什么?我已经看到一些测试套件示例显示反向循环更快,但我找不到任何解释为什么!
我假设它是因为循环不再需要在每次检查它是否完成时评估属性并且它只是检查最终的数值.
即
for (var i = count - 1; i >= 0; i--)
{
// count is only evaluated once and then the comparison is always on 0.
}
Run Code Online (Sandbox Code Playgroud)
ale*_*nis 889
它不是那么i--快i++.实际上,他们都同样快.
升序循环需要花费时间的是评估每个i数组的大小.在这个循环中:
for(var i = array.length; i--;)
Run Code Online (Sandbox Code Playgroud)
.length当您声明时i,您只评估一次,而对于此循环
for(var i = 1; i <= array.length; i++)
Run Code Online (Sandbox Code Playgroud)
当你检查是否.length增加时i,你会评估每次增量i <= array.length.
在大多数情况下,您甚至不应该担心这种优化.
Tom*_*ter 197
这个人在很多浏览器中比较了javascript中的很多循环.他还有一个测试套件,所以你可以自己运行它们.
在所有情况下(除非我在阅读中错过了一个),最快的循环是:
var i = arr.length; //or 10
while(i--)
{
//...
}
Run Code Online (Sandbox Code Playgroud)
X''*_*X'' 127
我试着用这个答案给出一个广泛的图景.
括号中的以下想法是我的信念,直到我刚刚测试了这个问题:
[[对于像C/C++这样的低级语言,编译代码使得当变量为零(或非零)时处理器具有特殊的条件跳转命令.
此外,如果你关心这么多的优化,你可以去代替,因为是一个单处理器命令,而不是意味着.]] ++ii++++ii++j=i+1, i=j
真正的快速循环可以通过展开它们来完成:
for(i=800000;i>0;--i)
do_it(i);
Run Code Online (Sandbox Code Playgroud)
它可能比慢
for(i=800000;i>0;i-=8)
{
do_it(i); do_it(i-1); do_it(i-2); ... do_it(i-7);
}
Run Code Online (Sandbox Code Playgroud)
但其原因可能非常复杂(仅举几例,游戏中存在处理器命令预处理和缓存处理的问题).
就高级语言而言,如您所问的JavaScript,如果您依赖库,内置函数进行循环,则可以优化.让他们决定如何做得最好.
因此,在JavaScript中,我建议使用类似的东西
array.forEach(function(i) {
do_it(i);
});
Run Code Online (Sandbox Code Playgroud)
它也不易出错,浏览器有机会优化您的代码.
[备注:不仅是浏览器,而且你也有空间可以轻松优化,只需重新定义forEach功能(浏览器依赖),以便它使用最新的最佳技巧!:) @AMK说在特殊情况下值得使用array.pop或者array.shift.如果你那样做,就把它放在幕后.的最大矫枉过正是添加选项,forEach选择循环算法.]
此外,对于低级语言,最佳实践是如果可能的话,使用一些智能库函数进行复杂的循环操作.
这些库也可以将东西(多线程)放在背后,专业程序员也可以使它们保持最新状态.
我做了更多的审查,事实证明,在C/C++中,即使对于5e9 =(50,000x100,000)操作,如果测试是针对像@alestanis这样的常量进行的,那么上升和下降之间没有区别.(JsPerf结果有时不一致,但大体上说的一样:你不能让一个很大的区别),
所以--i恰好是一个相当"豪华"的事情.它只会让你看起来像一个更好的程序员.:)
另一方面,为了展开这个5e9的情况,当我走了10秒时,它让我从12秒降到2.5秒,当我走了20秒时,它降到了2.1秒.没有优化,优化使得事情变得无法实现.:)(展开可以在我上面的方式或使用i++,但这不会带来JavaScript的前方.)
总而言之:保持i--/ i++和++i/ i++差异到求职面试,坚持array.forEach或其他复杂的图书馆功能可用.;)
sai*_*iuc 33
i-- 和...一样快 i++
下面的代码与您的代码一样快,但使用了一个额外的变量:
var up = Things.length;
for (var i = 0; i < up; i++) {
Things[i]
};
Run Code Online (Sandbox Code Playgroud)
建议不要每次都评估数组的大小.对于大型阵列,可以看到性能下降.
dre*_*ash 21
既然,您对这个主题感兴趣,请看一下Greg Reimer关于JavaScript循环基准的博客文章,在JavaScript中编写循环的最快方法是什么?:
我为JavaScript中的不同编码循环方法构建了一个循环基准测试套件.已经有一些已经存在,但我没有发现任何承认本机数组和HTML集合之间的区别.
您还可以通过打开对循环执行性能测试https://blogs.oracle.com/greimer/resource/loop-test.html(如果JavaScript在浏览器中被阻止,则不起作用,例如,NoScript).
编辑:
Milan Adamovsky创建的最新基准测试可以在此处针对不同的浏览器在运行时执行.
var i, result = 0;
for (i = steps - 1; i; i--) {
result += i;
}
Run Code Online (Sandbox Code Playgroud)
最快的是:
var result = 0;
for (var i = steps - 1; i >= 0; i--) {
result += i;
}
Run Code Online (Sandbox Code Playgroud)

Dr *_*ams 19
它不是--或者++,它是比较操作.有了--您可以使用与0的比较,同时用++你需要将它与长度进行比较.在处理器上,与零比较通常是可用的,而与有限整数相比则需要减法.
a++ < length
实际编译为
a++
test (a-length)
Run Code Online (Sandbox Code Playgroud)
因此编译时处理器需要更长的时间.
H.-*_*itt 15
对于普通代码,特别是像JavaScript这样的高级语言,在i++和中没有性能差异i--.
性能标准是在for循环和比较语句中的使用.
这适用于所有高级语言,并且大部分独立于JavaScript的使用.解释是底线的结果汇编代码.
循环中可能出现性能差异.背景是在汇编程序代码级别上,您可以看到a compare with 0只是一个不需要额外寄存器的语句.
这种比较是在循环的每次通过时发出的,并且可以导致可测量的性能改进.
for(var i = array.length; i--; )
Run Code Online (Sandbox Code Playgroud)
将被评估为这样的伪代码:
i=array.length
:LOOP_START
decrement i
if [ i = 0 ] goto :LOOP_END
... BODY_CODE
:LOOP_END
Run Code Online (Sandbox Code Playgroud)
请注意,0是文字,或者换句话说,是一个常量值.
for(var i = 0 ; i < array.length; i++ )
Run Code Online (Sandbox Code Playgroud)
将被评估为这样的伪代码(假设正常的解释器优化):
end=array.length
i=0
:LOOP_START
if [ i < end ] goto :LOOP_END
increment i
... BODY_CODE
:LOOP_END
Run Code Online (Sandbox Code Playgroud)
注意end是一个需要CPU寄存器的变量.这可能会调用代码中的附加寄存器交换,并且在语句中需要更昂贵的比较if语句.
对于高级语言而言,可读性(促进可维护性)作为次要的性能改进更为重要.
通常,从数组开始到结束的经典迭代更好.
从数组结束到开始的更快迭代导致可能不需要的反向序列.
正如评论中所要求的那样:在减少之前或之后的评估中的差异--i和.i--i
最好的解释是尝试一下;-)这是一个Bash示例.
% i=10; echo "$((--i)) --> $i"
9 --> 9
% i=10; echo "$((i--)) --> $i"
10 --> 9
Run Code Online (Sandbox Code Playgroud)
BBo*_*Bog 14
我在Sublime Text 2中看过同样的建议.
就像已经说过的那样,主要的改进不是在for循环中每次迭代时评估数组的长度.这是一种众所周知的优化技术,当数组是HTML文档的一部分(for为所有li元素执行)时,在JavaScript中特别有效.
例如,
for (var i = 0; i < document.getElementsByTagName('li').length; i++)
比...慢得多
for (var i = 0, len = document.getElementsByTagName('li').length; i < len; i++)
从我的立场来看,你问题中形式的主要改进是它没有声明一个额外的变量(len在我的例子中)
但是如果你问我,重点不在于i++vs i--优化,而是在每次迭代时不必评估数组的长度(你可以在jsperf上看到一个基准测试).
Pav*_*l P 13
我认为在JavaScript中说它i--更快是不合理的i++.
首先,它完全依赖于JavaScript引擎实现.
其次,如果最简单的构造JIT并转换为本机指令,那么i++vs i--将完全依赖于执行它的CPU.也就是说,在ARM(移动电话)上,由于在单个指令中执行递减和比较为零,因此降低到0会更快.
也许,你认为一个人比另一个人更浪漫,因为建议的方式是
for(var i = array.length; i--; )
Run Code Online (Sandbox Code Playgroud)
但建议的方式不是因为一个比另一个快,而只是因为如果你写
for(var i = 0; i < array.length; i++)
Run Code Online (Sandbox Code Playgroud)
然后在每次迭代array.length都必须进行评估(更聪明的JavaScript引擎或许可以弄清楚循环不会改变数组的长度).即使它看起来像一个简单的语句,它实际上是一些由JavaScript引擎在引擎盖下调用的函数.
另一个原因,为什么i--可以被认为是"更快"是因为JavaScript引擎只需要分配一个内部变量来控制循环(变量为var i).如果你将array.length或其他变量进行比较,则必须有多个内部变量来控制循环,而内部变量的数量是JavaScript引擎的有限资产.循环中使用的变量越少,JIT进行优化的机会就越大.这就是为什么i--可以被认为更快......
A.M*_*M.K 13
由于其他答案似乎都没有回答您的具体问题(其中一半以上显示C示例并讨论低级语言,您的问题是针对JavaScript)我决定编写自己的问题.
所以,你走了:
简单回答: i--通常更快,因为每次运行时都不必将比较运行为0,各种方法的测试结果如下:
测试结果:由这个 jsPerf "证明" ,arr.pop()实际上是迄今为止最快的循环.但是,专注于--i,i--,i++和++i你在你的问题问,这里有jsPerf(他们是从多个jsPerf的,请参见下面的源)结果总结:
--i并且i--在Firefox中i--是相同的,而在Chrome中更快.
在Chrome中,基本for循环(for (var i = 0; i < arr.length; i++))比在Firefox中更快i--,--i而在Firefox中则更慢.
在Chrome和Firefox中arr.length,Chrome的速度显着提高了大约170,000 ops/sec.
没有显着差异,++i比i++大多数浏览器AFAIK 更快,它在任何浏览器中都不会相反.
简短摘要: arr.pop()是迄今为止最快的循环; 对于特别提到的循环,i--是最快的循环.
来源: http ://jsperf.com/fastest-array-loops-in-javascript/15,http://jsperf.com/ipp-vs-ppi-2
我希望这回答了你的问题.
你现在做的方式并没有更快(除了它是一个无限循环,我猜你打算做i--.
如果你想让它更快,请执行以下操作:
for (i = 10; i--;) {
//super fast loop
}
Run Code Online (Sandbox Code Playgroud)
当然你不会在这么小的循环中注意到它。它更快的原因是因为您在检查 i 为“真”时递减 i (当它达到 0 时评估为“假”)
可以通过JavaScript(以及所有语言)最终将其转换为在CPU上运行的操作码来解释.CPU始终只有一条指令用于与零进行比较,这很快.
顺便说一句,如果你能保证count永远>= 0,你可以简化为:
for (var i = count; i--;)
{
// whatever
}Run Code Online (Sandbox Code Playgroud)
这不取决于--或++符号,但它取决于您在循环中应用的条件.
例如:如果变量的静态值比每次循环检查条件(如数组的长度或其他条件)更大,则循环速度更快.
但是不要担心这种优化,因为这次它的效果是以纳秒为单位.
for(var i = array.length; i--; )速度不是很快.但是当你替换array.length时super_puper_function(),可能会明显更快(因为它在每次迭代中被调用).这就是区别.
如果您打算在2014年进行更改,则无需考虑优化.如果您要使用"搜索和替换"进行更改,则无需考虑优化.如果您没有时间,则无需考虑优化.但现在,你有时间考虑它.
PS:i--不快i++.
简而言之:在JavaScript中执行此操作绝对没有区别.
首先,您可以自己测试一下:
您不仅可以在任何JavaScript库中测试和运行任何脚本,而且还可以访问大量以前编写的脚本,以及查看不同平台上不同浏览器的执行时间差异的能力.
因此,就您所见,任何环境中的性能都没有区别.
如果要提高脚本的性能,可以尝试执行以下操作:
var a = array.length;声明,以便每次循环时都不会计算其值但你必须明白,你可以获得的改善是如此微不足道,大多数你甚至不应该关心它.
很久很久以前,有一个共同的机器指令,DSZ(减少并略过零).使用汇编语言编程的人使用此指令实现循环以保存寄存器.现在这个古老的事实已经过时了,我相信你不会在使用这种伪改进的任何语言中获得任何性能提升.
我认为这种知识在我们这个时代传播的唯一方式就是当你阅读另一个人的代码时.看到这样的结构,并问为什么它实现了,在这里答案:"它提高了性能,因为它比较为零".你对同事的更高知识感到困惑,并认为使用它更聪明:-)
正如alestani指出的那样,在升序循环中花费时间的一件事是,为每次迭代评估数组的大小.在这个循环中:
for ( var i = 1; i <= array.length; i++ )
Run Code Online (Sandbox Code Playgroud)
你.length每次增加时都会评估i.在这一个:
for ( var i = 1, l = array.length; i <= l; i++ )
Run Code Online (Sandbox Code Playgroud)
.length当你申报时,你只评估一次i.在这一个:
for ( var i = array.length; i--; )
Run Code Online (Sandbox Code Playgroud)
比较是隐式的,它在递减之前发生i,并且代码非常易读.然而,什么可以产生一个很大的差异,是你放在循环中.
循环调用函数(在别处定义):
for (i = values.length; i-- ;) {
add( values[i] );
}
Run Code Online (Sandbox Code Playgroud)
循环内联代码:
var sum = 0;
for ( i = values.length; i-- ;) {
sum += values[i];
}
Run Code Online (Sandbox Code Playgroud)
如果你可以内联你的代码,而不是在不牺牲易读性的情况下调用函数,那么你可以使循环速度提高一个数量级!
注意:随着浏览器越来越擅长内联简单函数,它实际上取决于代码的复杂程度.所以,优化前的配置文件,因为
但要记住:
编写代码供人们阅读,并且只是偶然为机器执行.
++vs.--无关紧要,因为 JavaScript 是一种解释型语言,而不是一种编译型语言。每条指令都翻译成一种以上的机器语言,你不应该关心血腥的细节。
谈论使用--(或++)来有效使用汇编指令的人是错误的。这些指令适用于整数运算,JavaScript中没有整数,只有 numbers。
您应该编写可读的代码。