2017-05-08 26 views
10

在我搜索具體數字以支持在Javascript中使用const關鍵字時,我偶然發現了所有三個變量聲明類型var,let和const之間的性能比較。我不喜歡測試設置,所以我創建了a simplified onefor循環中的javascript'let'和'var'

沒想到太大的區別和Firefox指標達到了我的期望:

jsPerf results on Firefox 52

但在鉻奇怪的事情發生了:

jsPerf results on Chrome 57

不僅所有的測試結果明顯降低但環內的let分解爲速度的一小部分。

我決定在Browserstack中運行測試,以確保它不是我古怪的Linux設置。在Windows 10上,Firefox 53Chrome 58也發生了同樣的情況。我甚至測試了一些較老的Chrome 50,並得到了相同的行爲。

這是怎麼回事?這是一個錯誤嗎?

編輯:有人評論說,循環可能只是優化,因爲它什麼都不做。爲了表明,事實並非如此,我改變了the test

+0

您確定Firefox不只是優化代碼嗎?這些代碼塊實際上沒有做任何事情,所以可能是他們在速度上相似的原因。 – CodingIntrigue

+0

_「我創建了一個簡化的。」_你基本上刪除了整個測試。你創建了一個什麼都不做,因此得到優化的循環。 「讓裏面」甚至沒有副作用,這就是爲什麼它是「最快」的原因。 Chrome的引擎似乎沒有優化這種特殊情況。 – zeroflagL

+0

@CodingIntrigue:我想到了這一點,但運行一個空循環將導致數量顯着增加(我的機器上大約1800萬)。 – koehr

回答

0

這是因爲let關鍵字對於規範來說有些新意,只適用於本地範圍。在Chrome中,它似乎尚未進行優化,但這應該只是時間問題。

+0

有趣的是,在任何其他瀏覽器中,Safari和Edge都不會發生這種情況。 編輯:但 - 如預期的 - 在Opera中,它使用與Chrome相同的引擎。 – koehr

2

當您使用let時,for循環的主體必須創建一個新的作用域來處理循環變量的正確生存期,但在很多情況下,可以優化掉額外的代碼和運行時。例如,考慮下面的代碼:

let sum = 0; 
let fns = []; 
for (let i=0; i < 1000; i++) { 
    function foo() { sum += i; } 

    fns.push(foo); 

} 

當您通過babeljs運行它,你可以看到它產生相當於ES5代碼包括,以保持正確的變量壽命的函數調用:

var sum = 0; 
var fns = []; 

var _loop = function _loop(i) { 
    function foo() { 
    sum += i; 
    } 

    fns.push(foo); 
}; 

for (var i = 0; i < 1000; i++) { 
    _loop(i); 
} 

然而, babel足夠聰明,如果你沒有做任何需要延長循環變量使用壽命的事情,它只需使用一個普通的for循環與內聯體。所以,你的代碼:

for (let i=0; i < 1000; i++) { 
    true; 
} 

可以被證明是完全等價:

for (var i=0; i < 1000; i++) { 
    true; 
} 

我的猜測是非常類似的東西在內部發生在Chrome,但他們還沒有優化掉的情況下,他們不必讓循環變量保持活躍狀態​​。

看到我在這個例子的頂部使用的代碼在Firefox和Chrome中的比較會很有趣,因爲我懷疑它們最終應該同樣緩慢。你應該小心計時的東西,比如空循環,因爲優化的結果可能會偏離實際代碼的正常值。

+1

*「我的猜測是*」 - 可靠的來源。 –

+0

jsPerf中有一個編輯按鈕。您可以隨時在新版本中添加此版本。我很感興趣,因爲Chrome是唯一沒有優化它的瀏覽器。 – koehr

+1

@Kinduser謝謝,但我發現我的猜測通常很可靠。至少和互聯網上的任何東西一樣可靠。我所做的是對這個問題給出了一個建議的答案。任何人都可以自由引用支持或反駁我的答案的引用,如果他們這樣做,我會更新我的答案或相應地刪除它。 – Duncan