增量后与增量前-Javascript优化

增量后与增量前-Javascript优化,javascript,optimization,increment,Javascript,Optimization,Increment,我在浏览谷歌代码时,偶然发现了一个名为JSpeed-OptimizationforJavaScript的项目 我注意到其中一个优化是将for循环语句中的I++更改为++I 优化前 for (i=0;i<1;i++) {} for (var i = 0, j = 0; i < 1000000; i++, j++) { if (i == 4) { var tmp = i / 2; } if ((i % 2) == 0) { va

我在浏览谷歌代码时,偶然发现了一个名为JSpeed-OptimizationforJavaScript的项目

我注意到其中一个优化是将for循环语句中的
I++
更改为
++I

优化前

for (i=0;i<1;i++) {}

for (var i = 0, j = 0; i < 1000000; i++, j++) {
    if (i == 4) {
        var tmp = i / 2;
    }

    if ((i % 2) == 0) {
        var tmp = i / 2;
        i++;
    }
}
var arr = new Array(1000000);
for (i = 0; i < arr.length; i++) {}
for(var i=0;i<1;++i){}
for(var i=0,j=0;i<1000000;++i,++j){if(i==4){var tmp=i>>1;}
if((i&1)==0){var tmp=i>>1;i++;}}
var arr=new Array(1000000);for(var i=0,arr_len=arr.length;i<arr_len;++i){}
(i=0;i>1;i++;}
var arr=new Array(1000000);for(var i=0,arr_len=arr.length;i优化不是前后增量。它是使用按位“shift”和“and”运算符,而不是除法和模


还有一种优化方法是缩小javascript以减小总大小(但这不是运行时优化)。

听起来像是过早的优化。当你的应用程序快完成时,检查瓶颈在哪里,并根据需要进行优化。但是如果你想全面了解循环性能,请查看以下内容:

但是,由于JS引擎的改进和浏览器之间的差异,您永远不知道这将在何时过时。最好的选择是在出现问题之前不要担心它。让您的代码清晰易读


编辑:根据pre与post的对比,这在统计上是无关紧要的。(pre可能更糟)

这是我读到的,可以回答你的问题:“preincrement(
++I
)将一个值添加到
i
,然后返回
i
;相反,
i++
返回
i
,然后将一个值添加到该值中,这在理论上导致在应用增量操作之前创建一个临时变量来存储
i
的值。”.

刚刚在firebug中进行了测试,没有发现后期增量和前期增量之间的差异。这可能是在其他平台上进行的优化? 以下是我的firebug测试代码:

function test_post() {
    console.time('postIncrement');
    var i = 1000000, x = 0;
    do x++; while(i--);
    console.timeEnd('postIncrement');
}

function test_pre() {
    console.time('preIncrement');
    var i = 1000000, x = 0;
    do ++x; while(i--);
    console.timeEnd('preIncrement');
}

test_post();
test_pre();
test_post();
test_pre();
test_post();
test_pre();
test_post();
test_pre();
输出为:

postIncrement: 140ms
preIncrement: 160ms
postIncrement: 136ms
preIncrement: 157ms
postIncrement: 148ms
preIncrement: 137ms
postIncrement: 136ms
preIncrement: 148ms

这是一个错误的优化。据我所知,您正在保存1个操作代码。如果您希望使用此技术优化代码,那么您走错了方向。而且,大多数编译器/解释器都会为您优化此操作()简言之,我不会担心。但是,如果你真的担心,你应该使用
I+=1

这是我刚刚做的又快又脏的基准测试

var MAX = 1000000, t=0,i=0;

t = (new Date()).getTime();
for ( i=0; i<MAX;i++ ) {}
t = (new Date()).getTime() - t;

console.log(t);

t = (new Date()).getTime();
for ( i=0; i<MAX;++i ) {}
t = (new Date()).getTime() - t;

console.log(t);

t = (new Date()).getTime();
for ( i=0; i<MAX;i+=1 ) {}
t = (new Date()).getTime() - t;

console.log(t);
删除最低和最高值

Post    Pre     +=
1071    ----    1060
1065    ----    ----
1070    1065    1060
----    1070    1060
1070    1063    ----
1066    1060    1064
----    1063    1054
平均值

Post    Pre     +=
1071    1073    1060
1065    1048    1051
1070    1065    1060
1090    1070    1060
1070    1063    1068
1066    1060    1064
1053    1063    1054
1068.4  1064.2  1059.6

请注意,这超过了一百万次迭代,结果平均在9毫秒内。考虑到JavaScript中的大多数迭代处理都是在更小的集合(例如DOM容器)上完成的,因此这算不上什么优化。

这可能是cargo cult编程。 当您为没有任意运算符重载的语言使用合适的编译器/解释器时,这应该没有什么区别

<优化> C++对

有意义
T x = ...;
++x
可以就地修改值,而

T x = ...;
x++
必须通过在引擎盖下做一些事情来创建副本,比如

T x = ...;
T copy;
(copy = T(x), ++x, copy)

对于大型结构类型或在其“复制构造函数”中执行大量计算的类型来说,这可能会很昂贵。

Anatoliy的测试在预增量测试函数中包含一个后增量:(

以下是没有副作用的结果

function test_post() {
    console.time('postIncrement');
    var i = 1000000, x = 0;
    do x++; while(i--);
    console.timeEnd('postIncrement');
}

function test_pre() {
    console.time('preIncrement');
    var i = 1000000, x = 0;
    do ++x; while(--i);
    console.timeEnd('preIncrement');
}

test_post();
test_pre();
test_post();
test_pre();
test_post();
test_pre();
test_post();
test_pre();
输出

postIncrement: 3.21ms
preIncrement: 2.4ms
postIncrement: 3.03ms
preIncrement: 2.3ms
postIncrement: 2.53ms
preIncrement: 1.93ms
postIncrement: 2.54ms
preIncrement: 1.9ms

这是一个很大的区别。

理论上,使用增量后操作符可能会产生一个临时值。在实践中,JavaScript编译器非常聪明,可以避免这种情况,尤其是在这种微不足道的情况下

例如,让我们考虑一下示例代码:

sh$ cat test.js 
function preInc(){
  for(i=0; i < 10; ++i)
    console.log(i);
}

function postInc(){
  for(i=0; i < 10; i++)
    console.log(i);
}

// force lazy compilation
preInc();
postInc();
当然,其他JavaScript编译器/解释器可能不这样做,但这是值得怀疑的


作为最后一个词,尽管如此,但我认为最好的做法是在可能的时候使用预增量:因为我经常切换语言,我更喜欢使用正确的语义来支持我想要的语法,而不是依赖编译器的灵活性。例如,现代C++编译器也不会有任何区别。对于重载的

运算符+++

而言,使用后增量会造成堆栈溢出。为什么?开始和结束总是返回相同的值,而不首先递增

函数reverseString(string=[],start=0,end=string.length-1){
如果(开始>=结束)返回
让温度=字符串[开始]
字符串[开始]=字符串[结束]
字符串[结束]=临时
//不要这样做
//反向字符串(字符串,开始++,结束--)
反向限制(字符串,++开始,--结束)
返回数组
}
让数组=[“H”、“a”、“n”、“n”、“a”、“H”]

console.log(反向限制(数组))
优化是否意味着将所有代码压缩在一起以使其不可读?Genius!不。优化实际上是改进和加速代码的某些部分,使其高效并降低CPU成本。将代码压缩在一起以使其不可读也可称为打包或缩小-这不是必要的优化,因为解包需要时间。既然解析器什么时候不需要解包了?这里的优化是传输,而不是性能。在许多其他语言/编译器中也是如此。实际上有一个优化,2的除法已经被一个正确的狗屎操作所取代。有一些证据表明pre和post确实有区别。…取决于引擎。你能提供一个来源吗?这对我来说没有多大意义。我知道还有其他优化。但是如果这不被认为是优化的一部分,那么为什么JSpeed会费心把这篇文章改成预增量?链接没有提到任何关于预增量和后增量的内容。是的。我的错误。忽略m关于我所说的,我有模糊的记忆,在阅读一些测试时,它确实起到了作用。它更多的是增量部分,而不是访问数组的方式。我知道如何使用
(i=0;我在你的链接中没有看到任何讨论前后增量的内容。哈!我是瞎子。我的链接中没有前后增量。现在正在检查正确的参考。我已经在firefox上做了测试。也没有太大差异。另一个答案给出了理论
sh$ node --version
v8.9.4
sh$ node --print-bytecode test.js | sed -nEe '/(pre|post)Inc/,/^\[/p'
[generating bytecode for function: preInc]
Parameter count 1
Frame size 24
   77 E> 0x1d4ea44cdad6 @    0 : 91                StackCheck 
   87 S> 0x1d4ea44cdad7 @    1 : 02                LdaZero 
   88 E> 0x1d4ea44cdad8 @    2 : 0c 00 03          StaGlobalSloppy [0], [3]
   94 S> 0x1d4ea44cdadb @    5 : 0a 00 05          LdaGlobal [0], [5]
         0x1d4ea44cdade @    8 : 1e fa             Star r0
         0x1d4ea44cdae0 @   10 : 03 0a             LdaSmi [10]
   94 E> 0x1d4ea44cdae2 @   12 : 5b fa 07          TestLessThan r0, [7]
         0x1d4ea44cdae5 @   15 : 86 23             JumpIfFalse [35] (0x1d4ea44cdb08 @ 50)
   83 E> 0x1d4ea44cdae7 @   17 : 91                StackCheck 
  109 S> 0x1d4ea44cdae8 @   18 : 0a 01 0d          LdaGlobal [1], [13]
         0x1d4ea44cdaeb @   21 : 1e f9             Star r1
  117 E> 0x1d4ea44cdaed @   23 : 20 f9 02 0f       LdaNamedProperty r1, [2], [15]
         0x1d4ea44cdaf1 @   27 : 1e fa             Star r0
  121 E> 0x1d4ea44cdaf3 @   29 : 0a 00 05          LdaGlobal [0], [5]
         0x1d4ea44cdaf6 @   32 : 1e f8             Star r2
  117 E> 0x1d4ea44cdaf8 @   34 : 4c fa f9 f8 0b    CallProperty1 r0, r1, r2, [11]
  102 S> 0x1d4ea44cdafd @   39 : 0a 00 05          LdaGlobal [0], [5]
         0x1d4ea44cdb00 @   42 : 41 0a             Inc [10]
  102 E> 0x1d4ea44cdb02 @   44 : 0c 00 08          StaGlobalSloppy [0], [8]
         0x1d4ea44cdb05 @   47 : 77 2a 00          JumpLoop [42], [0] (0x1d4ea44cdadb @ 5)
         0x1d4ea44cdb08 @   50 : 04                LdaUndefined 
  125 S> 0x1d4ea44cdb09 @   51 : 95                Return 
Constant pool (size = 3)
Handler Table (size = 16)
[generating bytecode for function: get]
[generating bytecode for function: postInc]
Parameter count 1
Frame size 24
  144 E> 0x1d4ea44d821e @    0 : 91                StackCheck 
  154 S> 0x1d4ea44d821f @    1 : 02                LdaZero 
  155 E> 0x1d4ea44d8220 @    2 : 0c 00 03          StaGlobalSloppy [0], [3]
  161 S> 0x1d4ea44d8223 @    5 : 0a 00 05          LdaGlobal [0], [5]
         0x1d4ea44d8226 @    8 : 1e fa             Star r0
         0x1d4ea44d8228 @   10 : 03 0a             LdaSmi [10]
  161 E> 0x1d4ea44d822a @   12 : 5b fa 07          TestLessThan r0, [7]
         0x1d4ea44d822d @   15 : 86 23             JumpIfFalse [35] (0x1d4ea44d8250 @ 50)
  150 E> 0x1d4ea44d822f @   17 : 91                StackCheck 
  176 S> 0x1d4ea44d8230 @   18 : 0a 01 0d          LdaGlobal [1], [13]
         0x1d4ea44d8233 @   21 : 1e f9             Star r1
  184 E> 0x1d4ea44d8235 @   23 : 20 f9 02 0f       LdaNamedProperty r1, [2], [15]
         0x1d4ea44d8239 @   27 : 1e fa             Star r0
  188 E> 0x1d4ea44d823b @   29 : 0a 00 05          LdaGlobal [0], [5]
         0x1d4ea44d823e @   32 : 1e f8             Star r2
  184 E> 0x1d4ea44d8240 @   34 : 4c fa f9 f8 0b    CallProperty1 r0, r1, r2, [11]
  168 S> 0x1d4ea44d8245 @   39 : 0a 00 05          LdaGlobal [0], [5]
         0x1d4ea44d8248 @   42 : 41 0a             Inc [10]
  168 E> 0x1d4ea44d824a @   44 : 0c 00 08          StaGlobalSloppy [0], [8]
         0x1d4ea44d824d @   47 : 77 2a 00          JumpLoop [42], [0] (0x1d4ea44d8223 @ 5)
         0x1d4ea44d8250 @   50 : 04                LdaUndefined 
  192 S> 0x1d4ea44d8251 @   51 : 95                Return 
Constant pool (size = 3)
Handler Table (size = 16)