2017-04-21 28 views
5

我注意到其他question循環中的性能差異,同時使用letvar變量聲明。Javascript臨時死區NodeJS 7.9.0性能下降?

初始問題是正確地回答的是,在使用let for循環較慢因爲let創建用於每次迭代保持let聲明的變量的值的新範圍。要做更多的工作,所以慢一些是正常的。正如參考,我給的代碼和的NodeJS(7.9.0)的執行時間的結果:

請注意,以下關於版本的NodeJS所有的JavaScript代碼7.9.0

常規代碼:

'use strict'; 
console.time('var'); 
for (var i = 0; i < 100000000; i++) {} 
console.timeEnd('var'); 


console.time('let'); 
for (let j = 0; j < 100000000; j++) {} 
console.timeEnd('let'); 

輸出:

var: 55.792ms 
let: 247.123ms 

爲了避免在循環的每次迭代中額外聲明j,我們在循環之前聲明j變量。可以預料,現在這應該使let循環性能匹配var之一。 但是沒有!這是代碼,結果以供參考:循環之前定義

代碼let

'use strict'; 
console.time('var'); 
for (var i = 0; i < 100000000; i++) {} 
console.timeEnd('var'); 


console.time('let'); 
let j; 
for (j = 0; j < 100000000; j++) {} 
console.timeEnd('let'); 

輸出:

var: 231.249ms 
let: 233.485ms 

我們可以看到,不僅let循環沒有得到任何更快,但var循環變得像let一樣慢!唯一的解釋是,由於我們不在任何塊或函數中,因此這兩個變量都在全局模塊範圍內聲明。然而,如here所示,範圍中間的變量的let聲明創建了時間死區,這使j變量未初始化,而var初始化如定義的變量。

所以雖然未初始化的變量沒有被引用的時間死區運行的代碼,必須相當慢....

最後以顯示尊重,我們聲明的程序頂部的j變量顯示運行它的結果沒有暫時死區

代碼不具有時間盲區:

'use strict'; 
let j; 
console.time('var'); 
for (var i = 0; i < 100000000; i++) {} 
console.timeEnd('var'); 


console.time('let'); 
for (j = 0; j < 100000000; j++) {} 
console.timeEnd('let'); 

輸出:

var: 55.586ms 
let: 55.009ms 

現在無論letvar循環也有類似的性能優化!

有沒有人知道我對假死區性能的假設是否正確,或提供不同的解釋?

+0

有趣的問題 - upvoted,你也應該在其他環境中嘗試。 –

+0

我也很好奇那個,可能是關於內存分配的東西 –

+0

這與TDZ絕對有關。請參閱[「性能」項目的要點](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified#tdz-is-everywhere-except-in-transpilers-and-engines)。這在我的腦海中是有道理的,但對我來說寫一個答案還不夠好。 –

回答

2

這是你的測試節點上的多個版本的輸出:

node-v4.0.0 
var: 92ms 
let: 336ms 
var: 220ms 
let: 230ms 
===== 
node-v4.2.2 
var: 95ms 
let: 342ms 
var: 228ms 
let: 233ms 
===== 
node-v5.1.0 
var: 93.418ms 
let: 342.050ms 
var: 264.895ms 
let: 228.310ms 
===== 
node-v5.12.0 
var: 103.254ms 
let: 340.990ms 
var: 228.698ms 
let: 228.213ms 
===== 
node-v6.3.1 
var: 109.476ms 
let: 338.127ms 
var: 232.381ms 
let: 241.795ms 
===== 
node-v6.5.0 
var: 96.630ms 
let: 339.570ms 
var: 686.631ms 
let: 612.820ms 
===== 
node-v6.7.0 
var: 106.760ms 
let: 349.677ms 
var: 690.753ms 
let: 587.444ms 
===== 
node-v7.0.0 
var: 95.366ms 
let: 333.880ms 
var: 222.668ms 
let: 234.101ms 
===== 
node-v7.4.0 
var: 101.074ms 
let: 330.778ms 
var: 221.869ms 
let: 238.053ms 
===== 
node-v7.8.0 
var: 93.604ms 
let: 338.447ms 
var: 224.263ms 
let: 233.313ms 
===== 
node-v7.9.0 
var: 92.622ms 
let: 333.552ms 
var: 275.980ms 
let: 230.990ms 

是不是所有的節點版本,只是我在本地安裝,所以很容易測試的。

顯然,在大多數版本中,這種行爲是一致的:將let放在循環的外面會使其稍微更快一點,但它會讓var變得更慢。

似乎6.5.0中發生了一些不好的事情,但它被固定爲7.x.

它可以留下一些優化的地方,但我不會太擔心var變得越來越慢。我會更快地讓let感興趣。

將這些示例轉化爲函數並讓它們運行多次可以使JIT啓動並優化函數,因此結果可能會與第一次運行時看到的結果不同。