为了账号安全,请及时绑定邮箱和手机立即绑定

后增量与前增量-Javascript优化

后增量与前增量-Javascript优化

慕雪6442864 2019-11-30 14:45:32
当我偶然发现名为JSpeed-Javascript优化的项目时,我正在浏览Google Code。我注意到优化之一是更改i++为++ifor循环语句。优化之前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){}我知道前后的增量是什么,但是知道如何加快代码速度吗?
查看完整描述

3 回答

?
繁星点点滴滴

TA贡献1803条经验 获得超3个赞

这是我阅读并可以回答你的问题:“前递增(++i)加一的值i,然后返回i;相反,i++收益i则增加了一个给它,这在理论上中创建一个临时变量存储的值的结果i在执行增量操作之前”。


查看完整回答
反对 回复 2019-11-30
?
哔哔one

TA贡献1854条经验 获得超8个赞

这是一个伪优化。据我了解,您正在保存1个操作码。如果您正在寻找使用这种技术优化代码的方法,那么您走错了路。另外,大多数编译器/解释器都会为您优化此过程(参考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    1073    1060

1065    1048    1051

1070    1065    1060

1090    1070    1060

1070    1063    1068

1066    1060    1064

1053    1063    1054

删除最低和最高


Post    Pre     +=

1071    ----    1060

1065    ----    ----

1070    1065    1060

----    1070    1060

1070    1063    ----

1066    1060    1064

----    1063    1054

平均值


1068.4  1064.2  1059.6

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


查看完整回答
反对 回复 2019-11-30
?
ibeautiful

TA贡献1993条经验 获得超5个赞

从理论上讲,使用后递增运算符可能会产生一个临时值。实际上,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();

在这种情况下,NodeJS中的V8编译器会生成完全相同的字节码(尤其是在操作码39-44中查找增量):


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)

当然,其他JavaScript编译器/解释器可能会这样做,但这是令人怀疑的。


最后,无论如何,我还是认为在可能的情况下使用预增量是一种最佳实践:由于我经常切换语言,因此我宁愿使用具有正确语义的语法来实现自己想要的目的,而不是依赖于编译器聪明。例如,现代C编译器也没有任何区别。但是在C ++中,这对重载可能会产生重大影响operator++。


查看完整回答
反对 回复 2019-11-30
  • 3 回答
  • 0 关注
  • 550 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信