Javascript var vs let (des) otimização / problema de lentidão na v8 e SpiderMonkey
Durante a refatoração do código JavaScript no meu projeto, descobri que alguns dos meus loops diminuíram drasticamente. Procurando pela causa raiz que encontreiesta pergunta SO afirmando que a desaceleração é causada porlet
declaração dentrofor
criação de loop e fechamento. Para minha surpresa em movimentolet
e fechamento dofor
loop não ajudou, e mesmo usandovar
ao invés delet
A variável for loop também não ajuda, porque a desaceleração é causada porlet
colocadadepois de afor
ciclo. Ao remover detalhes adicionais, obtive este trecho de código:
"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
})();
(também emJS Fiddle Nota: o uso do JS Fiddle mostra resultados um pouco diferentes, mas lentidão semelhante ainda está presente nos mesmos lugares)
A execução no Chrome produz os seguintes
without_let: 122ms
let_below: 411ms <----------- Slowdown for v8
let_above_and_in_loop: 153ms
let_in_loop: 137ms
Alguns estudos me trouxeram parao artigo declarando issolet
desoptimização causada antes do Chrome 56 / V8 5.6! mas meu cromo é 57.0.2987.133 (64 bits) e v8 ver 5.7.492.71. Mais surpresas ao tentar executar isso no Firefox 52.0.2 (32 bits). Aqui temos desaceleração em outro local, quando a variável criada comlet
é usado dentro do fechamento:
without_let: 101.9ms
let_below: 99ms
let_above_and_in_loop: 899ms <----- Slowdown for SpiderMonkey
let_in_loop: 102ms
A meu ver, o problema está um pouco relacionado ao chamado recurso "Zona morta temporal", mas ainda não está claro:
Por que dois principais navegadores (principais mecanismos JavaScript) ainda não conseguem otimizar essas partes (diferentes) do snippet?
Existem soluções alternativas para continuar usandolet
(exceto usando Babel para transformar let em var)? Suponha que eu possa passar opções para o Chrome ou mesmo diretamente para a v8 viav8::V8::SetFlagsFromCommandLine(&argc, argv, true);
UPD: Na versão 58.0.3029.96 do Chrome, versão v8 5.8.283.37 correspondente (de acordo comhttps://omahaproxy.appspot.com/) depois de ativar o chrome: // flags / # enable-v8-future como o jmrk sugeriu abaixo, ainda há lentidão no terceiro caso (agora 2 vezes em vez de 8 vezes)
without_let: 157.000ms
let_below: 155.000ms
let_above_and_in_loop: 304.000ms
let_in_loop: 201.000ms
Firefox 53.0 (32 bits)
without_let: 278.650ms
let_below: 310.290ms
let_above_and_in_loop: 848.325ms
let_in_loop: 275.495ms