当我偶然发现这个名为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){}
我知道前后增量的作用,但是任何想法如何加速代码?
答案 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))