在v8和SpiderMonkey中的Javascript var vs let(de)优化/减速问题 [英] Javascript var vs let (de)optimization/slowdown issue in v8 and SpiderMonkey

查看:96
本文介绍了在v8和SpiderMonkey中的Javascript var vs let(de)优化/减速问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的项目中的JavaScript代码重构过程中,我发现我的一些循环显着减慢。搜索根本原因我发现这个SO问题表明减速是由 let 声明中的循环和闭包创建引起的。
令我惊喜的是,中的循环关闭没有帮助,甚至使用 var 而不是 let for循环变量也没有帮助,因为减速是由 let
通过删除额外的细节,我已经获得了这个代码片段:



 use strictconsole.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 '); // 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; //< ---通知let而不是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 = i){f();} var totals = 0; console.timeEnd('let_in_loop'); // chrome:137ms,FF:102ms})();  



(也在 JS Fiddle 注意:使用JS Fiddle显示一点点不同的结果,但同样的地方仍然存在类似的放缓)



运行此在Chrome上生成以下

  without_let:122ms 
let_below:411ms< ---------- - v8的减速
let_above_and_in_loop:153ms
let_in_loop:137ms

我要文章,指出 let 在Chrome 56 / V8之前引发了最佳化5.6!但我的铬是57.0.2987.133(64位)和v8版本5.7.492.71。
想要在Firefox 52.0.2(32位)上运行这个更多的惊喜。这里我们在另一个地方放缓,当使用 let 创建的变量在封闭中使用时:

 code> without_let:101.6ms 
let_below:99ms
let_above_and_in_loop:899ms< ----- SpiderMonkey的减速
let_in_loop:102ms

由于我看到的问题与所谓的时间死区功能有些相关,但仍不清楚:


  1. 为什么两个主要的浏览器(主要的JavaScript引擎)仍然无法优化片段的不同部分?


  2. 有没有任何解决方法继续使用 let 除了使用Babel将其转换为var)?假设我可以通过 v8 :: V8 :: SetFlagsFromCommandLine(& argc,argv,true);

    将选项传递给Chrome,甚至直接传递到v8

UPD:
在Chrome ver 58.0.3029.96中,对应v8版本5.8.283.37在启用chrome:// flags /#enable后,接受 https://omahaproxy.appspot.com/ ) -v8 - 未来如下面建议的第三种情况(现在是2次而不是8次)仍然放缓。

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

Firefox 53.0(32位)

  without_let:278.650ms 
let_below:310.290ms
let_above_and_in_loop:848.325ms
let_in_loop:275.495ms


解决方案

我可以回答V8部分的问题。您所看到的减速是由于旧的优化编译器(称为曲轴)的限制。这一直没有得到解决,因为团队一直在忙于开发新的优化编译器(Turbofan),它在Chrome 59(目前在加那利和开发频道上,Beta版!不久之后)发货。 / p>

在Chrome 58(目前在测试版)中,您可以通过将实验JavaScript编译管道设置为已启用(铬://标志/#启用-V8-将来)。请注意,Chrome 59将有几个额外的性能改进。



备注:在现有的代码库中,迁移到 let ,所以你可以继续使用 var


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

解决方案

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.

这篇关于在v8和SpiderMonkey中的Javascript var vs let(de)优化/减速问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆