Dlaczego wartość typeof null zmienia się wewnątrz pętli?


109

Wykonywanie tego fragmentu kodu w konsoli Chrome:

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

powinien drukować 1000 razy false, ale na niektórych komputerach będzie drukować falseprzez kilka iteracji, a potem trueprzez resztę.

wprowadź opis obrazu tutaj

Dlaczego to się dzieje? Czy to tylko błąd?


4
Dla mnie to powraca 1000 razy ...
Hoàng Long,

2
Myślę, że to błąd, mam 262 fałszywe / 738 prawdziwe
Jax Teller

1
jest to coś dziwnego z konsolą Chrome'a: jeśli wypchniesz do tablicy i zarejestrujesz tablicę, to wszystko false. tak jak jest, liczba trues waha się w chromie.
dandavis

1
@ HoàngDługo, jak powiedziałem w pytaniu, dzieje się to tylko na niektórych komputerach. Możliwe też, że dzieje się to tylko na niektórych wersjach Chrome
Agos

2
@ HoàngLong, upewnij się, że korzystasz z przeglądarki Chrome
Nobita,

Odpowiedzi:



37

W rzeczywistości jest to błąd silnika JavaScript V8 ( Wiki ).

Ten silnik jest używany w Chromium, Maxthron, Android OS, Node.js itp.

Względnie prosty opis błędu można znaleźć w tym temacie na Reddicie :

Nowoczesne silniki JavaScript kompilują kod JS w zoptymalizowany kod maszynowy podczas jego wykonywania (kompilacja Just In Time), aby działał szybciej. Jednak etap optymalizacji wiąże się z pewnym początkowym kosztem wydajności w zamian za długoterminowe przyspieszenie, więc silnik dynamicznie decyduje, czy metoda jest tego warta, w zależności od tego, jak często jest używana.

W tym przypadku wydaje się, że błąd występuje tylko w zoptymalizowanej ścieżce, podczas gdy niezoptymalizowana ścieżka działa dobrze. Na początku metoda działa zgodnie z przeznaczeniem, ale jeśli jest wywoływana w pętli wystarczająco często, w pewnym momencie silnik zdecyduje się ją zoptymalizować i zastąpi ją błędną wersją.

Wydaje się, że ten błąd został naprawiony w samym V8 ( zatwierdzenie ), a także w Chromium ( zgłoszenie błędu ) i NodeJS ( zatwierdzenie ).


Potwierdziłem, że błąd nadal występuje w Node.js 6.2.2, co mnie niepokoi.
Michael Shops w dniu

Zostało to naprawione dzisiaj w silniku V8 (21.06), wierzę, że wkrótce powiązane oprogramowanie zostanie zaktualizowane.
Sergey Novikov

Backportowanie poprawki v8 do Node.js 6.2.x jest już w toku jako numer 7348 należący do TheAlphaNerd .
Michael Shops w dniu

18

Aby odpowiedzieć na bezpośrednie pytanie, dlaczego to się zmienia, błąd tkwi w procedurze optymalizacji „JIT” silnika V8 JS używanego przez Chrome. Na początku kod jest uruchamiany dokładnie tak, jak został napisany, ale im częściej go uruchamiasz, tym większy potencjał korzyści z optymalizacji przewyższają koszty analizy.

W takim przypadku po powtórnym wykonaniu w pętli kompilator JIT analizuje funkcję i zastępuje ją wersją zoptymalizowaną. Niestety analiza przyjmuje błędne założenie, a zoptymalizowana wersja w rzeczywistości nie daje poprawnego wyniku.

W szczególności użytkownik Reddit RainHappens sugeruje , że jest to błąd w propagacji typu :

Wykonuje również propagację pewnego typu (jak w przypadku typów zmiennych itp.). Istnieje specjalny typ „niewykrywalny”, gdy zmienna jest niezdefiniowana lub zerowa. W tym przypadku optymalizator przyjmuje komunikat „null jest niewykrywalny, więc można go zastąpić ciągiem„ undefined ”do porównania.

Jest to jeden z poważnych problemów z optymalizacją kodu: jak zagwarantować, że kod, który został zmieniony pod kątem wydajności, będzie nadal miał taki sam efekt jak oryginał.


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.