Warum ändert sich der Wert von typeof null innerhalb einer Schleife?

109

Ausführen dieses Snippets in der Chrome-Konsole:

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

sollte 1000 Mal gedruckt werden false, aber auf einigen Computern wird falsefür eine Reihe von Iterationen gedruckt , dann truefür den Rest.

Geben Sie hier die Bildbeschreibung ein

Warum passiert dies? Ist es nur ein Fehler?

Agos
quelle
4
Es kehrt 1000-mal wahr für mich zurück ...
Hoàng Long
2
Ich denke, es ist ein Fehler, ich habe 262 falsch / 738 wahr
Jax Teller
1
Es ist etwas Seltsames an der Chrome-Konsole: Wenn Sie auf ein Array pushen und das Array protokollieren, ist alles false. wie es ist, trueschwankt die Anzahl von s in Chrom.
Dandavis
1
@ HoàngLong wie gesagt in der Frage, passiert es nur auf einigen Maschinen. Es ist auch möglich, dass es nur auf einigen Versionen von Chrome
Agos
2
@ HoàngLong stellen Sie sicher, dass Sie es in Chrome ausführen
Nobita

Antworten:

37

Es ist eigentlich ein Fehler in der V8 JavaScript Engine ( Wiki ).

Diese Engine wird in Chromium, Maxthron, Android OS, Node.js usw. verwendet.

Relativ einfache Fehlerbeschreibung finden Sie in diesem Reddit-Thema :

Moderne JavaScript-Engines kompilieren JS-Code bei der Ausführung in optimierten Maschinencode (Just In Time-Kompilierung), damit er schneller ausgeführt wird. Der Optimierungsschritt hat jedoch einige anfängliche Leistungskosten im Austausch für eine langfristige Beschleunigung, sodass der Motor dynamisch entscheidet, ob sich eine Methode lohnt, je nachdem, wie häufig sie verwendet wird.

In diesem Fall scheint es nur im optimierten Pfad einen Fehler zu geben, während der nicht optimierte Pfad einwandfrei funktioniert. Die Methode funktioniert also zunächst wie beabsichtigt, aber wenn sie irgendwann oft genug in einer Schleife aufgerufen wird, entscheidet sich die Engine, sie zu optimieren und durch die fehlerhafte Version zu ersetzen.

Dieser Fehler scheint in V8 selbst (haben fest verpflichten ), aswell wie in Chrom ( Bug - Report ) und NodeJS ( commit ).

Sergey Novikov
quelle
Ich habe bestätigt, dass der Fehler immer noch in Node.js 6.2.2 enthalten ist, was mich beunruhigt.
Michael Shopsin
Es wurde heute (21.06) in der V8-Engine behoben. Ich glaube, dass bald verwandte Software aktualisiert wird.
Sergey Novikov
Das Backportieren des v8-Fixes auf Node.js 6.2.x wird bereits als Problem Nr. 7348 von TheAlphaNerd durchgeführt .
Michael Shopsin
18

Um die direkte Frage zu beantworten, warum es sich ändert, befindet sich der Fehler in der Optimierungsroutine "JIT" der von Chrome verwendeten V8 JS-Engine. Zunächst wird der Code genau so ausgeführt, wie er geschrieben wurde. Je mehr Sie ihn ausführen, desto größer ist jedoch das Potenzial, dass die Vorteile der Optimierung die Kosten für die Analyse überwiegen.

In diesem Fall analysiert der JIT-Compiler nach wiederholter Ausführung in der Schleife die Funktion und ersetzt sie durch eine optimierte Version. Leider geht die Analyse von einer falschen Annahme aus und die optimierte Version liefert nicht das richtige Ergebnis.

Insbesondere schlägt Reddit Benutzer RainHappens , dass es ein Fehler in Art Ausbreitungs :

Es wird auch eine Typweitergabe durchgeführt (wie bei welchen Typen eine Variable usw. sein kann). Es gibt einen speziellen "nicht nachweisbaren" Typ, wenn eine Variable undefiniert oder null ist. In diesem Fall lautet der Optimierer "Null ist nicht erkennbar, sodass er für den Vergleich durch die Zeichenfolge" undefiniert "ersetzt werden kann.

Dies ist eines der größten Probleme bei der Optimierung des Codes: Wie kann sichergestellt werden, dass der Code, der für die Leistung neu angeordnet wurde, immer noch den gleichen Effekt wie das Original hat?

IMSoP
quelle