Por que o valor de typeof null muda dentro de um loop?

109

Executando este snippet no console do Chrome:

function foo() {
    return typeof null === 'undefined';
}
for(var i = 0; i < 1000; i++) console.log(foo());

deve imprimir 1000 vezes false, mas em algumas máquinas imprimirá falsepor várias iterações e depois truepara o resto.

insira a descrição da imagem aqui

Por que isso está acontecendo? É apenas um bug?

Agos
fonte
4
Está voltando 1000 vezes verdade para mim ...
Hoàng Long
2
acho que é bug, tenho 262 falso / 738 verdadeiro
Jax Teller
1
é algo estranho com o console do Chrome: se você enviar para um array e registrar o array, é tudo false. como está, o número detrue s flutua no cromo.
dandavis
1
@ HoàngLong como eu disse na pergunta, isso acontece apenas em algumas máquinas. Também é possível que isso aconteça apenas em algumas versões do Chrome
Agos
2
@ HoàngLong certifique-se de executá-lo no Chrome
Nobita

Respostas:

37

Na verdade, é um bug do motor V8 JavaScript ( Wiki ).

Este mecanismo é usado no Chromium, Maxthron, sistema operacional Android, Node.js etc.

Uma descrição de bug relativamente simples que você pode encontrar neste tópico do Reddit :

Os mecanismos JavaScript modernos compilam o código JS em código de máquina otimizado quando é executado (compilação Just In Time) para torná-lo executado mais rápido. No entanto, a etapa de otimização tem algum custo de desempenho inicial em troca de uma aceleração de longo prazo, de modo que o mecanismo decide dinamicamente se um método vale a pena, dependendo da frequência com que é usado.

Nesse caso, parece haver um bug apenas no caminho otimizado, enquanto o caminho não otimizado funciona bem. Portanto, a princípio, o método funciona conforme o planejado, mas se for chamado em um loop com frequência suficiente em algum ponto, o mecanismo decidirá otimizá-lo e substituí-lo pela versão com erros.

Este bug parece ter sido corrigido no próprio V8 ( commit ), bem como no Chromium ( relatório de bug ) e NodeJS ( commit ).

Sergey Novikov
fonte
Confirmei que o bug ainda está no Node.js 6.2.2, o que me preocupa.
Michael Shops em
Foi consertado no motor V8 hoje (21.06), acredito que em breve o software relacionado será atualizado.
Sergey Novikov de
O backport da correção da v8 para Node.js 6.2.x já está em andamento como o problema nº 7348 de propriedade de TheAlphaNerd .
Michael Shops em
18

Para responder à pergunta direta de por que ele muda, o bug está na rotina de otimização "JIT" do mecanismo V8 JS usado pelo Chrome. No início, o código é executado exatamente como escrito, mas quanto mais você o executa, mais potencial existe para que os benefícios da otimização superem os custos da análise.

Nesse caso, após a execução repetida no loop, o compilador JIT analisa a função e a substitui por uma versão otimizada. Infelizmente, a análise faz uma suposição incorreta e a versão otimizada não produz o resultado correto.

Especificamente, o usuário do Reddit RainHappens sugere que é um erro na propagação de tipo :

Ele também faz alguma propagação de tipo (como em quais tipos uma variável etc pode ser). Existe um tipo especial "indetectável" para quando uma variável é indefinida ou nula. Nesse caso, o otimizador torna-se "nulo é indetectável, portanto, pode ser substituído pela string" indefinida "para a comparação.

Este é um dos problemas difíceis com a otimização do código: como garantir que o código que foi reorganizado para desempenho ainda terá o mesmo efeito que o original.

IMSoP
fonte