'v8 JavaScript performance implications of const, let, and var?

Regardless of functional differences, does using the new keywords 'let' and 'const' have any generalized or specific impact on performance relative to 'var'?

After running the program:

function timeit(f, N, S) {
    var start, timeTaken;
    var stats = {min: 1e50, max: 0, N: 0, sum: 0, sqsum: 0};
    var i;
    for (i = 0; i < S; ++i) {
        start = Date.now();
        f(N);
        timeTaken = Date.now() - start;

        stats.min = Math.min(timeTaken, stats.min);
        stats.max = Math.max(timeTaken, stats.max);
        stats.sum += timeTaken;
        stats.sqsum += timeTaken * timeTaken;
        stats.N++
    }

    var mean = stats.sum / stats.N;
    var sqmean = stats.sqsum / stats.N;

    return {min: stats.min, max: stats.max, mean: mean, spread: Math.sqrt(sqmean - mean * mean)};
}

var variable1 = 10;
var variable2 = 10;
var variable3 = 10;
var variable4 = 10;
var variable5 = 10;
var variable6 = 10;
var variable7 = 10;
var variable8 = 10;
var variable9 = 10;
var variable10 = 10;

function varAccess(N) {
    var i, sum;
    for (i = 0; i < N; ++i) {
        sum += variable1;
        sum += variable2;
        sum += variable3;
        sum += variable4;
        sum += variable5;
        sum += variable6;
        sum += variable7;
        sum += variable8;
        sum += variable9;
        sum += variable10;
    }
    return sum;
}

const constant1 = 10;
const constant2 = 10;
const constant3 = 10;
const constant4 = 10;
const constant5 = 10;
const constant6 = 10;
const constant7 = 10;
const constant8 = 10;
const constant9 = 10;
const constant10 = 10;

function constAccess(N) {
    var i, sum;
    for (i = 0; i < N; ++i) {
        sum += constant1;
        sum += constant2;
        sum += constant3;
        sum += constant4;
        sum += constant5;
        sum += constant6;
        sum += constant7;
        sum += constant8;
        sum += constant9;
        sum += constant10;
    }
    return sum;
}


function control(N) {
    var i, sum;
    for (i = 0; i < N; ++i) {
        sum += 10;
        sum += 10;
        sum += 10;
        sum += 10;
        sum += 10;
        sum += 10;
        sum += 10;
        sum += 10;
        sum += 10;
        sum += 10;
    }
    return sum;
}

console.log("ctl = " + JSON.stringify(timeit(control, 10000000, 50)));
console.log("con = " + JSON.stringify(timeit(constAccess, 10000000, 50)));
console.log("var = " + JSON.stringify(timeit(varAccess, 10000000, 50)));

.. My results were the following:

ctl = {"min":101,"max":117,"mean":108.34,"spread":4.145407097016924}
con = {"min":107,"max":572,"mean":435.7,"spread":169.4998820058587}
var = {"min":103,"max":608,"mean":439.82,"spread":176.44417700791374}

However discussion as noted here seems to indicate a real potential for performance differences under certain scenarios: https://esdiscuss.org/topic/performance-concern-with-let-const



Solution 1:[1]

"LET" IS BETTER IN LOOP DECLARATIONS

With a simple test (5 times) in navigator like that:

// WITH VAR
console.time("var-time")
for(var i = 0; i < 500000; i++){}
console.timeEnd("var-time")

The mean time to execute is more than 2.5ms

// WITH LET
console.time("let-time")
for(let i = 0; i < 500000; i++){}
console.timeEnd("let-time")

The mean time to execute is more than 1.5ms

I found that loop time with let is better.

Solution 2:[2]

T.J. Crowder's answer is so excellent.

Here is an addition of: "When would I get the most bang for my buck on editing existing var declarations to const ?"

I've found that the most performance boost had to do with "exported" functions.

So if file A, B, R, and Z are calling on a "utility" function in file U that is commonly used through your app, then switching that utility function over to "const" and the parent file reference to a const can eak out some improved performance. It seemed for me that it wasn't measurably faster, but the overall memory consumption was reduced by about 1-3% for my grossly monolithic Frankenstein-ed app. Which if you're spending bags of cash on the cloud or your baremetal server, could be a good reason to spend 30 minutes to comb through and update some of those var declarations to const.

I realize that if you read into how const, var, and let work under the covers you probably already concluded the above... but in case you "glanced" over it :D.

From what I remember of the benchmarking on node v8.12.0 when I was making the update, my app went from idle consumption of ~240MB RAM to ~233MB RAM.

Solution 3:[3]

T.J. Crowder's answer is very good but :

  1. 'let' is made to make code more readable, not more powerful
  2. by theory let will be slower than var
  3. by practice the compiler can not solve completely (static analysis) an uncompleted program so sometime it will miss the optimization
  4. in any-case using 'let' will require more CPU for introspection, the bench must be started when google v8 starts to parse
  5. if introspection fails 'let' will push hard on the V8 garbage collector, it will require more iteration to free/reuse. it will also consume more RAM. the bench must take these points into account
  6. Google Closure will transform let in var...

The effect of the performance gape between var and let can be seen in real-life complete program and not on a single basic loop.

Anyway, to use let where you don't have to, makes your code less readable.

Solution 4:[4]

Just did some more tests, Initially I concluded that there is a substantial difference in favor of var. My results initially showed that between Const / Let / Var there was a ratio from 4 / 4 / 1 to 3 / 3 / 1 in execution time.

After Edit in 29/01/2022 (according to jmrk's remark to remove global variables in let and const tests) now results seem similar 1 / 1 / 1. I give the code used below. Just let me mention that I started from the code of AMN and did lots of tweaking, and editing.

I did the tests both in w3schools_tryit editor and in Google_scripts

My Notes:

  • In GoogleScripts there seems that the 1st test ALWAYS takes longer, no-matter which one, especially for reps<5.000.000 and before separating them in individual functions
  • For Reps < 5.000.000 JS engine optimizations are all that matters, results go up and down without safe conclusions
  • GoogleScripts constantly does ~1.5x time longer, I think it is expected
  • There was a BIG difference when all tests where separated in individual functions, execution speed was at-least doubled and 1st test's delay almost vanished!

Please don't judge the code, I did try but don't pretend to be any expert in JS. I would be delighted to see your tests and opinions.

function mytests(){
var start = 0;
var tm1=" Const: ", tm2=" Let: ", tm3=" Var: ";
    
start = Date.now();
tstLet();
tm2 += Date.now() - start;

start = Date.now();
tstVar();
tm3 += Date.now() - start;

start = Date.now();
tstConst();
tm1 += (Date.now() - start);

var result = "TIMERS:" + tm1 + tm2 + tm3;
console.log(result);
return result;
}

// with VAR
function tstVar(){
var lmtUp = 50000000;
var i=0;
var item = 2;
var sum = 0;

for(i = 0; i < lmtUp; i++){sum += item;}
item = sum / 1000;
}

// with LET
function tstLet(){
let lmtUp = 50000000;
let j=0;
let item = 2;
let sum=0;

for( j = 0; j < lmtUp; j++){sum += item;}
item = sum/1000;
}

// with CONST
function tstConst(){
const lmtUp = 50000000;
var k=0;
const item = 2;
var sum=0;

for( k = 0; k < lmtUp; k++){sum += item;}
k = sum / 1000;
}

Solution 5:[5]

code with 'let' will be more optimized than 'var' as variables declared with var do not get cleared when the scope expires but variables declared with let does. so var uses more space as it makes different versions when used in a loop.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Ankur Loriya
Solution 2 isaacdre
Solution 3 Michael Valve
Solution 4
Solution 5 Santanu Roy