@老赵 的一个微博“ 由eval生成的代码效率真的很差吗? http://t.cn/zWTUBEo 内含人身攻击,不喜勿入。”
引发了最近对eval火爆的讨论,教主 @Franky 和 灰大 @otakustay 也给了精彩的数据分析。
刚好之前也做过类似的测试,我也跟风凑个热闹,提供两组数据供大家参考。
更新1: 感谢灰大 @otakustay 的指导,为排除eval('')调用本身对结果的影响,增加一组新数据A3, B3。并对旧的全部数据重测。
更新2: 感谢莫大 @貘吃馍香 的强力拍砖,增加了1). A4, B4;A5,B5的eval覆盖后的测试数据; 2). A6,B6 eval别名;3). A7,B7 eval.call。
测试环境:
a. 机器:Intel(R) Corei7-2720 2.2Ghz (4核心8线程)、内存8Gb
b. OS:Windows 7 Enterprise SP1 64-bit
c. 浏览器:
b.1 Google Chrome 21.0.1180.79 m
b.2 Firefox 14.0.1
b.3 IE9.0.8112.16421
d. 测试方法
d.1 每个用例测试5次,耗时取最小值。
d.2 测试过程中没有开启Firebug或Chrome Console,开启这些工具会使时间倍增,很难在有效时间内得到该用例结果
用例A1:
我们在内联函数中调用空的eval("")
!function() {
var a = 1,
b = 2,
c = true;
function func() {
var d = 2;
e = !c;
eval("");
}
for (var i = 0; i func(i, i + 1, i + 2);
}
}();
用例A2:
注释掉内联函数中的eval("")
!function() {
var a = 1,
b = 2,
c = true;
function func() {
var d = 2;
e = !c;
//eval("");
}
for (var i = 0; i func(i, i + 1, i + 2);
}
}();
用例A3:
为排除eval("")调用本身产生的影响,我们在外层函数中调用eval("")
!function() {
var a = 1,
b = 2,
c = true;
function func() {
var d = 2;
e = !c;
}
for (var i = 0; i eval("");
func(i, i + 1, i + 2);
}
}();
用例A4:
将eval()函数覆盖成普通的空函数
function eval(){}
!function() {
var a = 1,
b = 2,
c = true;
function func() {
var d = 2;
e = !c;
eval("");
}
for (var i = 0; i func(i, i + 1, i + 2);
}
}();
用例A5:
同样是函数调用,不是eval而且另一个空函数f
function f(){}
!function() {
var a = 1,
b = 2,
c = true;
function func() {
var d = 2;
e = !c;
f("");
}
for (var i = 0; i func(i, i + 1, i + 2);
}
}();
用例A6:
将eval赋给另一个变量f,然后调用f
var f = eval;
!function() {
var a = 1,
b = 2,
c = true;
function func() {
var d = 2;
e = !c;
f("");
}
for (var i = 0; i func(i, i + 1, i + 2);
}
}();
用例A7:
使用eval.call的方式去调用
!function() {
var a = 1,
b = 2,
c = true;
function func() {
var d = 2;
e = !c;
eval.call(null, '');
}
for (var i = 0; i func(i, i + 1, i + 2);
}
}();
A组测试结果:
|
A1 |
A2 |
A3 |
A4 |
A5 |
A6 |
A7 |
A1 : A2 |
A1 : A3 |
A1 : A4 |
A4 : A5 |
Chrome |
1612ms |
8ms |
1244ms |
897ms |
7ms |
718ms |
680ms |
201.5 |
1.3 |
1.8 |
128.1 |
Firefox |
2468ms |
69ms |
732ms |
2928ms |
134ms |
5033ms |
4984ms |
35.8 |
3.4 |
0.8 |
21.9 |
IE |
1207ms |
23ms |
233ms |
1147ms |
37ms |
148ms |
224ms |
52.5 |
5.2 |
1.0 |
31.0 |
用例B1:
for (var i = 0; i !function() {
var a = 1,
b = 2,
c = true;
!function () {
var d = 2;
e = !c;
eval("");
}();
}();
}
用例B2:
for (var i = 0; i !function() {
var a = 1,
b = 2,
c = true;
!function () {
var d = 2;
e = !c;
//eval("");
}();
}();
}
用例B3:
for (var i = 0; i !function() {
var a = 1,
b = 2,
c = true;
!function () {
var d = 2;
e = !c;
}();
}();
eval("");
}
用例B4:
var eval = function(){}
for (var i = 0; i !function() {
var a = 1,
b = 2,
c = true;
!function () {
var d = 2;
e = !c;
eval("");
}();
}();
}
用例B5:
var f = function(){}
for (var i = 0; i !function() {
var a = 1,
b = 2,
c = true;
!function () {
var d = 2;
e = !c;
f("");
}();
}();
}
用例B6:
var f = eval;
for (var i = 0; i !function() {
var a = 1,
b = 2,
c = true;
!function () {
var d = 2;
e = !c;
f("");
}();
}();
}
用例B7:
for (var i = 0; i !function() {
var a = 1,
b = 2,
c = true;
!function () {
var d = 2;
e = !c;
eval.call(null, '');
}();
}();
}
B组测试结果:
|
B1 |
B2 |
B3 |
B4 |
B5 |
B6 |
B7 |
B1 : B3 |
B1 : B2 |
B1 : B4 |
B4 : B5 |
Chrome |
1569ms |
134ms |
1093ms |
1022ms |
173ms |
830ms |
916ms |
11.7 |
1.4 |
1.5 |
5.9 |
Firefox |
5334ms |
1017ms |
5503ms |
5280ms |
1171ms |
6797ms |
6883ms |
5.2 |
1.0 |
1.0 |
4.5 |
IE |
3933ms |
560ms |
680ms |
4118ms |
583ms |
745ms |
854ms |
7.0 |
5.8 |
1.0 |
111.3 |
结论(仅限于文中的CASE):
1. eval本身的重复调用非常耗时,即使是空的eval("");
2. eval对内联函数执行效率有所影响,依具体环境、代码有所不同;
3. 我们可以看到无论哪种浏览器,无论是A组还是B组,2 和 5速度较佳。说明例中内联函数的eval无论以何种方式调用(即使eval被空函数覆盖)仍会对运行效率造成较大影响。推断是(黑盒推断,非权威,很可能是臆测)内联函数中只要发现eval,哪怕这个eval是被覆盖的空函数,在Scope Variables中都将会把所有的外部定义的变量等内容初始化到当前的Scope中。类似的,eval会对内联函数在运行时JS引擎的优化功能产生较大影响,降低执行效率。
4. 说点题外话,虽然没用IE10,而是IE9,在对eval的处理上,表现非常的优异。IE一直被开发人员诟病,但它的飞速成长也是值得肯定的,本例就是很好的一项证明。
更详细的原因剖析下列文章描述已十分详细,不再累述。欢迎拍砖:)尤其是莫大...
@老赵 的 《由eval生成的代码效率真的很差吗?》
@Franky 的 《Eval科普》
@otakustay 的 《浅谈Eval的影响》