2017-04-01 40 views
2

在我的项目中进行JavaScript代码重构期间,我发现一些循环显着减慢。寻找根本原因我发现this SO question陈述减速是由for循环和闭包创建中的let声明造成的。 令我惊讶的移动let和关闭了for循环没有帮助,甚至使用var代替let for循环变量也于事无补,因为经济放缓是由let引起的for循环之后放置。 通过去除多余的细节我获得此代码段:Javascript var和v8和SpiderMonkey中的优化/放慢问题

"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; 
 
\t \t console.timeEnd('let_in_loop'); //chrome: 137ms, FF:102ms 
 
})();

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

在Chrome运行这产生以下

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

一些谷歌搜索带我到the article,指出let导致Chrome 56/V8 5.6之前的优化!但我的chrome是57.0.2987.133(64位)和v8版本5.7.492.71。 更多的惊喜试图在Firefox 52.0.2(32位)上运行。在这里,我们有另外一个地方,减速时let创建的变量是内封闭使用:

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

当我看到这个问题在一定程度上涉及到所谓的“时间死区”的功能,但仍不清楚:

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

  2. 是否有任何变通办法继续使用let除了使用巴贝尔转让进VAR)?假设我能够通过v8::V8::SetFlagsFromCommandLine(&argc, argv, true);

UPD将选项传递到Chrome浏览器甚至直接V8: 在Chrome的版本58.0.3029.96,使镀铬后correspondng V8版本5.8.283.37(aconding到https://omahaproxy.appspot.com/) ://标志/#启用-V8-将来jmrk建议下面仍有放缓第三种情况(现2倍,而不是8倍)

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

火狐53.0(32位)

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

这不是他们*不能*,而是他们没有找到时间去实现它。您可能想要提交一些错误报告,以确定它们的优先顺序。 – Bergi

+1

这里是v8报告https://bugs.chromium.org/p/v8/issues/detail?id=6188 这里是FF https://support.mozilla.org/zh-CN/questions/1158956 –

+1

这里也是Bugzilla的项目https://bugzilla.mozilla.org/show_bug.cgi?id=1362930 –

回答

2

我可以回答问题的V8部分。您看到的放缓是由于旧优化编译器(称为“曲轴”)的限制。目前尚未解决这个问题,因为该团队一直忙于使用Chrome 59(目前在Canary和Dev频道,即将推出Beta版!)发布的新优化编译器(“Turbofan”)。

在Chrome 58(当前正在测试版)中,您可以通过将“实验性JavaScript编译流水线”设置为“启用”(位于chrome://flags/#enable-v8-future)来获得预览。请注意,Chrome 59将会有一些额外的性能改进。

备注:在现有的代码库中,迁移到let没有多大好处,因此您可以继续使用var

+0

我已经在Chrome版本58.0.3029.96中测试了这个 - 优化消除了剧烈的放缓,但仍然是第三种情况几乎慢了两倍。 –