3

During JavaScript code refactoring in my project I've found that some of my loops slowed down drastically. Searching for root cause I've found this SO question stating slowdown is caused by let statement inside for loop and closure creation. To my surprise moving let and closure out of the for loop didn't help, and even using var instead of let for loop variable also does not help because slowdown is caused by let placed after thefor loop. By removing extra details I've obtained this code snippet:

"use strict"
console.log("=========================");
(function(){
    var itr = 0;
    function f(){++itr;}
    console.time('without_let');
    for(var i = 0; i < 50000000; ++i){
        f();
    }
    var totals = 0;
    console.timeEnd('without_let'); //chrome: 122ms, FF:102ms
})();

(function(){
    var itr = 0;
    function f(){++itr;}
    console.time('let_below');
    for(var i = 0; i < 50000000; ++i){
        f();
    }
    let totals = 0; // <--- notice let instead of var
    console.timeEnd('let_below'); //chrome: 411ms, FF:99ms
})();

(function(){
    let itr = 0;
    function f(){++itr;}
    console.time('let_above_and_in_loop');
    for(let i = 0; i < 50000000; ++i){
        f();
    }
    var totals = 0;
    console.timeEnd('let_above_and_in_loop'); //chrome: 153ms, FF:899ms
})();

(function(){
    var itr = 0;
    function f(){++itr;}
    console.time('let_in_loop');
    for(let i = 0; i < 50000000; ++i){
        f();
    }
    var totals = 0;
  console.timeEnd('let_in_loop'); //chrome: 137ms, FF:102ms
})();

(also on JS Fiddle Note: using JS Fiddle shows little bit different results but similar slowdown is still present in the same places)

Running this on Chrome produces following

 without_let: 122ms
 let_below: 411ms <----------- Slowdown for v8
 let_above_and_in_loop: 153ms
 let_in_loop: 137ms

Some googling brought me to the article stating that let caused deoptimization prior to Chrome 56 / V8 5.6! but my chrome is 57.0.2987.133 (64-bit) and v8 ver 5.7.492.71. More surprises trying to run this on Firefox 52.0.2 (32-bit). Here we have slowdown in another place, when variable created with let is used inside closure:

 without_let: 101.9ms
 let_below: 99ms
 let_above_and_in_loop: 899ms <----- Slowdown for SpiderMonkey
 let_in_loop: 102ms

As I see the issue is somewhat related to so called "Temporal Dead Zone" feature, but still unclear:

  1. Why two major browsers (major JavaScript engines) still cannot optimize those (different) parts of the snippet?

  2. Are there any workarounds to keep using let (except using Babel to turn let into var)? Assume I'm able to pass options to Chrome or even directly to v8 via v8::V8::SetFlagsFromCommandLine(&argc, argv, true);

UPD: In Chrome ver 58.0.3029.96, correspondng v8 version 5.8.283.37 (aconding to https://omahaproxy.appspot.com/) after enabling chrome://flags/#enable-v8-future as jmrk suggested below there is still slowdown for third case (now 2 times instead of 8 times)

without_let: 157.000ms
let_below: 155.000ms
let_above_and_in_loop: 304.000ms
let_in_loop: 201.000ms

Firefox 53.0 (32bit)

without_let: 278.650ms
let_below: 310.290ms
let_above_and_in_loop: 848.325ms
let_in_loop: 275.495ms
Community
  • 1
  • 1
Chajnik-U
  • 501
  • 4
  • 8
  • 1
    It's not that they *cannot*, but rather that they didn't find the time to implement it yet. You might want to file some bug reports to get them prioritise this. – Bergi Apr 01 '17 at 12:42
  • 1
    Here is report for v8 https://bugs.chromium.org/p/v8/issues/detail?id=6188 and here for FF https://support.mozilla.org/en-US/questions/1158956 – Chajnik-U May 05 '17 at 10:04
  • 1
    Here is also Bugzilla item https://bugzilla.mozilla.org/show_bug.cgi?id=1362930 – Chajnik-U May 08 '17 at 07:15

1 Answers1

3

I can answer the V8 part of the question. The slowdown you're seeing is due to a limitation in the old optimizing compiler (known as "Crankshaft"). It hasn't been addressed in all this time because the team has been busy working on the new optimizing compiler ("Turbofan"), which is shipping in Chrome 59 (currently on the Canary and Dev channels, soon on Beta!).

In Chrome 58 (currently on Beta), you can already get a preview by setting the "Experimental JavaScript Compilation Pipeline" to "Enabled" (at chrome://flags/#enable-v8-future). Note that Chrome 59 will have a couple of additional performance improvements.

Side note: in an existing codebase, there isn't much benefit in migrating to let, so you could just keep using var.

jmrk
  • 34,271
  • 7
  • 59
  • 74
  • I've tested this in Chrome ver 58.0.3029.96 - optimization removed that drastic slowdown but still third case is almost two times slower. – Chajnik-U May 05 '17 at 09:07