在我的项目中进行JavaScript代码重构时,我发现我的一些循环速度急剧下降。寻找根本原因,我发现这个SO问题声称减速是由
for
循环内部的let
语句和闭包创建引起的。
令我惊讶的是,将let
和闭包移出for
循环并没有帮助,即使使用var
代替循环变量的let
也没有帮助,因为减速是由放置在for
循环后面的let
导致的。
通过去除额外的细节,我得到了这段代码片段:
"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
})();
在 Chrome 上运行此代码会产生以下结果:
(同样可以在 JS Fiddle 上查看。注意:使用 JS Fiddle 会显示略微不同的结果,但在相同位置仍会存在类似的减速现象。)
without_let: 122ms
let_below: 411ms <----------- Slowdown for v8
let_above_and_in_loop: 153ms
let_in_loop: 137ms
我通过一些搜索找到了这篇文章,它指出在Chrome 56 / V8 5.6之前,let
会导致去优化!但是我的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
我发现这个问题与所谓的“暂时性死区”功能有些相关,但仍然不清楚:
为什么两个主要浏览器(主要的JavaScript引擎)仍然无法优化代码片段中的这些(不同的)部分?
是否有任何解决方法来继续使用
let
( 除了 使用Babel将let变为var)?假设我能够通过v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
将选项传递给Chrome甚至直接传递给v8。
更新: 在Chrome版本58.0.3029.96,对应的v8版本是5.8.283.37(根据https://omahaproxy.appspot.com/),按照jmrk下面建议的启用chrome://flags/#enable-v8-future之后,第三种情况仍然会出现减速(现在是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