2017-04-21 62 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启动并优化函数,因此结果可能会与第一次运行时看到的结果不同。