Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript temporal dead zone NodeJS 7.9.0 performance decrease?

I have noticed in an other question the performance difference in loops while using let and var variables declaration.

The initial question is correctly answered that using let in the for loop is slower since let creates a new scope for each iteration to hold the value of let declared variable. More work to be done, so it is normal to be slower. Just as reference, I give the code and the results in NodeJS (7.9.0) execution time:

Please note that all javascript code below regards NodeJS version 7.9.0

Regular Code:

'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');

Output:

var: 55.792ms
let: 247.123ms

In order to avoid the extra scope declaration for j in every iteration of the loop, we declare the j variable just before the loop. One would expect that this should now make the let loop performance match the one of var. BUT NO!!! This is the code and the result for reference:

Code with let defined before loop:

'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');

Output:

var: 231.249ms
let: 233.485ms

We can see that, not only the let loop did not get any faster but also the var loop became as slow as the let one!!! The only explanation for this is that since we are not in any block or function, both variables are declared in the global module scope. However as referenced here, the let declaration of the variable in the middle of the scope, creates a temporal dead zone, which leaves the variable j uninitialized, while the var initializes the variable as defined.

So running code in a temporal dead zone although the uninitialized variable is not referenced, must be quite slower....

Finally to show the deference, we declare the j variable on top of the program to show the results of running it without the temporal dead zone.

Code without temporal dead zone:

'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');

Output:

var: 55.586ms
let: 55.009ms

Now both let and var loops have similar optimized performance!

Does anyone know whether my assumption about temporal dead zone performance is correct, or provide a different explanation???

like image 718
mitsos1os Avatar asked Apr 21 '17 10:04

mitsos1os


1 Answers

This is the output of your tests on several versions of Node:

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

Those are not all Node versions, just the ones that I have installed locally so it's easy to test.

Apparently the behavior is consistent in most of the versions: putting let outside of the loop makes it slightly faster, but it makes the var somewhere else much slower.

It seems that something bad happened in 6.5.0 but it was fixed 7.x.

It can leave some place for optimization but I wouldn't worry too much about var getting slower. I would be more interested of making let faster.

Making those examples into functions and letting them run several times can make the JIT kick in and optimize the functions so the results may differ from what you see when everything is run for the first time.

like image 121
rsp Avatar answered Sep 19 '22 06:09

rsp