引發了最近對eval火爆的討論,剛好之前也做過類似的測試,我也跟風湊個熱鬧,提供兩組數據供大家參考。
測試環境:
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("")
var a = 1,
b = 2,
c = true;
function func() {
var d = 2;
e = !c;
eval("");
}
for ( var i = 0; i < 2999999; i++) {
func(i, i + 1, i + 2);
}
}();
用例A2:
注釋掉內聯函數中的eval("")
var a = 1,
b = 2,
c = true;
function func() {
var d = 2;
e = !c;
//eval("");
}
for ( var i = 0; i < 2999999; i++) {
func(i, i + 1, i + 2);
}
}();
用例A3:
為排除eval("")調用本身產生的影響,我們在外層函數中調用eval("")
var a = 1,
b = 2,
c = true;
function func() {
var d = 2;
e = !c;
}
for ( var i = 0; i < 2999999; i++) {
eval("");
func(i, i + 1, i + 2);
}
}();
用例A4:
將eval()函數覆蓋成普通的空函數
!function() {
var a = 1,
b = 2,
c = true;
function func() {
var d = 2;
e = !c;
eval("");
}
for ( var i = 0; i < 2999999; i++) {
func(i, i + 1, i + 2);
}
}();
用例A5:
同樣是函數調用,不是eval而且另一個空函數f
!function() {
var a = 1,
b = 2,
c = true;
function func() {
var d = 2;
e = !c;
f("");
}
for ( var i = 0; i < 2999999; i++) {
func(i, i + 1, i + 2);
}
}();
用例A6:
將eval賦給另一個變量f,然后調用f
!function() {
var a = 1,
b = 2,
c = true;
function func() {
var d = 2;
e = !c;
f("");
}
for ( var i = 0; i < 2999999; i++) {
func(i, i + 1, i + 2);
}
}();
用例A7:
使用eval.call的方式去調用
var a = 1,
b = 2,
c = true;
function func() {
var d = 2;
e = !c;
eval.call(null, '');
}
for ( var i = 0; i < 2999999; 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:
!function() {
var a = 1,
b = 2,
c = true;
!function () {
var d = 2;
e = !c;
eval("");
}();
}();
}
用例B2:
!function() {
var a = 1,
b = 2,
c = true;
!function () {
var d = 2;
e = !c;
//eval("");
}();
}();
}
用例B3:
!function() {
var a = 1,
b = 2,
c = true;
!function () {
var d = 2;
e = !c;
}();
}();
eval("");
}
用例B4:
for ( var i = 0; i < 2999999; i++) {
!function() {
var a = 1,
b = 2,
c = true;
!function () {
var d = 2;
e = !c;
eval("");
}();
}();
}
用例B5:
for ( var i = 0; i < 2999999; i++) {
!function() {
var a = 1,
b = 2,
c = true;
!function () {
var d = 2;
e = !c;
f("");
}();
}();
}
用例B6:
for ( var i = 0; i < 2999999; i++) {
!function() {
var a = 1,
b = 2,
c = true;
!function () {
var d = 2;
e = !c;
f("");
}();
}();
}
用例B7:
!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一直被開發人員詬病,但它的飛速成長也是值得肯定的,本例就是很好的一項證明。