后增量与预增量 - Javascript优化

时间:2009-10-10 03:45:55

标签: javascript optimization increment

当我偶然发现这个名为JSpeed的项目 - Javascript优化时,我正在浏览Google Code。

我注意到其中一项优化是在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){}

我知道前后增量的作用,但是任何想法如何加速代码?

9 个答案:

答案 0 :(得分:56)

这是一种虚假优化。据我了解,你节省了1个操作码。如果您希望使用这种技术优化代码,那么您就走错了路。此外,大多数编译器/解释器无论如何都会为您优化(reference 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容器)完成的,并不是真正的优化。

答案 1 :(得分:46)

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

答案 2 :(得分:7)

理论上,使用后增量运算符可能产生一个临时值。在实践中,JavaScript编译器足够聪明,可以避免这种情况,特别是在这种微不足道的情况下。

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

operator++

在这种情况下,NodeJS中的V8编译器生成完全相同的字节码(例如,在操作码39-44处查看增量):

    # For each planet in the game (only non-destroyed planets are included)
    for key, planet in distances.items():
        # If the planet is owned
        if planet.is_owned():
            # Skip this planet
            continue

当然,其他JavaScript编译器/解释器可以做其他事情,但这是值得怀疑的。

总而言之,对于它的价值,我仍然认为在可能的情况下使用预增量是最好的做法:因为我经常切换语言,所以我更喜欢使用带有正确语义的语法为了我想要的,而不是依赖编译器的智能。例如,现代C编译器也没有任何区别。但是在C ++中,这会对重载distances = arr_distances(ship, game_map)产生重大影响。

答案 3 :(得分:3)

听起来像是过早优化。当您的应用程序即将完成时,请检查瓶颈所在并根据需要对其进行优化。但是如果你想要一个完整的循环性能指南,请查看:

http://blogs.oracle.com/greimer/entry/best_way_to_code_a

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

编辑:根据this guy,前期与后期在统计上无关紧要。 (事先可能更糟)

答案 4 :(得分:2)

优化不是预增量与后增量。这是使用按位'shift'和'and'运算符而不是除和mod。

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

答案 5 :(得分:1)

这可能是货物崇拜节目。 当你为没有任意运算符重载的语言使用一个像样的编译器/解释器时,它应该没有什么区别。

这种优化对于C ++来说是有意义的

T x = ...;
++x

可以修改一个值,而

T x = ...;
x++

必须通过像

那样做一些内容来制作副本
T x = ...;
T copy;
(copy = T(x), ++x, copy)

对于大型结构类型或在其`copy构造函数中进行大量计算的类型来说可能是昂贵的。

答案 6 :(得分:1)

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

这是一个很大的不同。

答案 7 :(得分:0)

刚刚在萤火虫中测试它,发现后增量和前增量之间没有区别。也许这个优化其他平台? 这是我的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

答案 8 :(得分:0)

使用后增量会导致堆栈溢出。为什么? start 和 end 将始终返回相同的值而无需先递增

function reverseString(string = [],start = 0,end = string.length - 1) {  
  if(start >= end) return
  let temp = string[start]
  string[start] = string[end]
  string[end] = temp
  //dont't do this
  //reverseString(string,start++,end--)
  reverseString(string,++start,--end)
  return array
}

let array = ["H","a","n","n","a","h"]
console.log(reverseString(array))