Analysieren Browser Javascript bei jedem Laden einer Seite?

190

Analysieren Browser (IE und Firefox) verknüpfte Javascript-Dateien jedes Mal, wenn die Seite aktualisiert wird?

Sie können die Dateien zwischenspeichern, also werden sie wahrscheinlich nicht jedes Mal versuchen, sie herunterzuladen, aber da jede Seite im Wesentlichen separat ist, erwarte ich, dass sie alten Code abreißen und ihn erneut analysieren.

Dies ist ineffizient, obwohl vollkommen verständlich, aber ich frage mich, ob moderne Browser klug genug sind, um den Parsing-Schritt innerhalb von Websites zu vermeiden. Ich denke an Fälle, in denen eine Site eine Javascript-Bibliothek wie ExtJS oder jQuery usw. verwendet.

ajreal
quelle
4
Mein 2c: Ich bin der Meinung, dass die Leistungsvorteile des Zwischenspeicherns von analysierten Javascript-Dateien zu gering sind, als dass dies eine sinnvolle Optimierung wäre.
Itay Maman
2
Nach meinen Benchmarks könnte es tatsächlich eine Rolle spielen. Zum Beispiel beträgt die Ladezeit von jQuery etwa 30 ms (auf einem schnellen Desktop-Computer), von denen 20% den Code nur in eine ausführbare Darstellung analysieren und der Rest ihn ausführt, dh in diesem Fall das jQuery-Objekt initialisiert. Wenn Sie mobil sind und zwei oder drei Bibliotheken verwenden, kann diese Verzögerung relevant sein, da die JavaScript-Ausführung blockiert und die Seite im Wesentlichen leer ist, bis jedes JS-Skript in den Speicher geladen wird.
Djjeck

Antworten:

338

Dies sind die Details, die ich ausgraben konnte. Zunächst ist anzumerken, dass JavaScript zwar normalerweise als interpretiert und auf einer VM ausgeführt betrachtet wird, dies jedoch bei modernen Interpreten, die dazu neigen, die Quelle direkt in Maschinencode zu kompilieren (mit Ausnahme des IE), nicht wirklich der Fall ist.


Chrome: V8-Motor

V8 verfügt über einen Kompilierungscache. Hiermit wird kompiliertes JavaScript unter Verwendung eines Hash der Quelle für bis zu 5 Garbage Collections gespeichert. Dies bedeutet, dass zwei identische Teile des Quellcodes einen Cache-Eintrag im Speicher gemeinsam nutzen, unabhängig davon, wie sie enthalten waren. Dieser Cache wird nicht gelöscht, wenn Seiten neu geladen werden.

Quelle


Update - 19/03/2015

Das Chrome-Team hat Details zu seinen neuen Techniken für das Streaming und Caching von JavaScript veröffentlicht .

  1. Skript-Streaming

Skript-Streaming optimiert das Parsen von JavaScript-Dateien. [...]

Ab Version 41 analysiert Chrome asynchrone und verzögerte Skripte in einem separaten Thread, sobald der Download begonnen hat. Dies bedeutet, dass das Parsen nur Millisekunden nach Abschluss des Downloads abgeschlossen werden kann und das Laden von Seiten um bis zu 10% schneller erfolgt.

  1. Code-Caching

Normalerweise kompiliert die V8-Engine bei jedem Besuch das JavaScript der Seite und wandelt es in Anweisungen um, die ein Prozessor versteht. Dieser kompilierte Code wird dann verworfen, sobald ein Benutzer von der Seite weg navigiert, da der kompilierte Code zum Zeitpunkt der Kompilierung stark vom Status und Kontext des Computers abhängt.

In Chrome 42 wird eine erweiterte Technik zum Speichern einer lokalen Kopie des kompilierten Codes eingeführt, sodass beim Herunterladen auf die Seite alle Schritte zum Herunterladen, Parsen und Kompilieren übersprungen werden können. Auf diese Weise kann Chrome bei allen Seitenladevorgängen etwa 40% der Kompilierungszeit vermeiden und auf Mobilgeräten wertvollen Akku sparen.


Oper: Carakan-Motor

In der Praxis bedeutet dies, dass wir jedes Mal, wenn ein Skriptprogramm kompiliert werden soll, dessen Quellcode mit dem eines anderen kürzlich kompilierten Programms identisch ist, die vorherige Ausgabe des Compilers wiederverwenden und den Kompilierungsschritt vollständig überspringen. Dieser Cache ist sehr effektiv in typischen Browserszenarien, in denen Seite für Seite von derselben Site geladen wird, z. B. verschiedene Nachrichtenartikel von einem Nachrichtendienst, da jede Seite häufig dieselbe, manchmal sehr große Skriptbibliothek lädt.

Daher wird JavaScript beim erneuten Laden von Seiten zwischengespeichert. Zwei Anforderungen an dasselbe Skript führen nicht zu einer Neukompilierung.

Quelle


Firefox: SpiderMonkey Engine

SpiderMonkey verwendet Nanojitals natives Backend einen JIT-Compiler. Der Prozess des Kompilierens des Maschinencodes ist hier zu sehen . Kurz gesagt, es scheint , Skripte beim Laden neu zu kompilieren. Wenn wir uns jedoch die Interna von genauer ansehen,Nanojit sehen wir, dass der übergeordnete Monitor jstracer, der zum Verfolgen der Kompilierung verwendet wird, während der Kompilierung drei Phasen durchlaufen kann und folgende Vorteile bietet Nanojit:

Der Ausgangszustand des Trace-Monitors ist die Überwachung. Dies bedeutet, dass Spidermonkey Bytecode interpretiert. Jedes Mal, wenn spidermonkey einen Rückwärtssprung-Bytecode interpretiert, notiert der Monitor, wie oft der Wert des Sprungziel-Programmzählers (PC) gesprungen wurde. Diese Zahl wird als Trefferzahl für den PC bezeichnet. Wenn die Trefferzahl eines bestimmten PCs einen Schwellenwert erreicht, wird das Ziel als heiß angesehen.

Wenn der Monitor feststellt, dass ein Ziel-PC heiß ist, prüft er in einer Hashtabelle mit Fragmenten, ob ein Fragment nativen Code für diesen Ziel-PC enthält. Wenn ein solches Fragment gefunden wird, wechselt es in den Ausführungsmodus. Andernfalls wechselt es in den Aufnahmemodus.

Dies bedeutet, dass für hotCodefragmente der native Code zwischengespeichert wird. Dies bedeutet, dass dies nicht neu kompiliert werden muss. Es wird nicht klargestellt, dass diese nativen Hash-Abschnitte zwischen den Seitenaktualisierungen beibehalten werden. Aber ich würde annehmen, dass sie es sind. Wenn jemand Belege dafür finden kann, dann ausgezeichnet.

EDIT : Es wurde darauf hingewiesen, dass Mozilla-Entwickler Boris Zbarsky erklärt hat, dass Gecko kompilierte Skripte noch nicht zwischenspeichert . Entnommen aus dieser SO-Antwort .


Safari: JavaScriptCore / SquirelFish Engine

Ich denke, dass die beste Antwort für diese Implementierung bereits von jemand anderem gegeben wurde .

Derzeit wird der Bytecode (oder der native Code) nicht zwischengespeichert. Es ist eine
Option, die wir in Betracht gezogen haben. Derzeit ist die Codegenerierung jedoch ein
trivialer Teil der JS-Ausführungszeit (<2%). Daher verfolgen wir
dies derzeit nicht.

Dies wurde von Maciej Stachowiak , dem Hauptentwickler von Safari, geschrieben. Ich denke, wir können das als wahr ansehen.

Ich konnte keine andere Informationen finden , aber Sie können mehr über die Verbesserungen in der Geschwindigkeit der neuesten lesen SquirrelFish ExtremeMotor hier , sehen Sie den Quellcode hier , wenn Sie etwas Zeit mitbringen.


IE: Chakra-Motor

In diesem Feld gibt es keine aktuellen Informationen zur JavaScript Engine (Chakra) von IE9. Wenn jemand etwas weiß, bitte kommentieren.

Dies ist ziemlich inoffiziell, aber für die älteren Engine-Implementierungen des IE gibt Eric Lippert ( ein MS-Entwickler von JScript ) in einer Blog-Antwort hier Folgendes an :

JScript Classic verhält sich wie eine kompilierte Sprache in dem Sinne, dass wir vor der Ausführung eines JScript Classic-Programms den Code vollständig syntaktisch überprüfen, einen vollständigen Analysebaum generieren und einen Bytecode generieren. Wir führen den Bytecode dann durch einen Bytecode-Interpreter. In diesem Sinne ist JScript genauso "kompiliert" wie Java. Der Unterschied besteht darin, dass Sie mit JScript unseren proprietären Bytecode nicht beibehalten oder überprüfen können . Außerdem ist der Bytecode viel höher als der JVM-Bytecode - die JScript Classic-Bytecode-Sprache ist kaum mehr als eine Linearisierung des Analysebaums, während der JVM-Bytecode eindeutig für den Betrieb auf einem Low-Level-Stack-Computer vorgesehen ist.

Dies deutet darauf hin, dass der Bytecode in keiner Weise bestehen bleibt und der Bytecode daher nicht zwischengespeichert wird.

Jivings
quelle
10
+1, ausgezeichnete Berichterstattung. In Bezug auf Firefox lesen Sie bitte diese StackOverflow-Frage, in der Mozilla-Entwickler Boris Zbarsky erklärt, dass Gecko dies derzeit nicht tut.
Cha0site
Danke, ich habe das auf meinen Reisen gesehen, konnte aber keine anderen Belege finden. Ich werde die Antwort damit bearbeiten.
Jivings
1
Beachten Sie, dass das, was über IE gesagt wurde, im Jahr 2003 gesagt wurde: IE9s JS-Engine erste Veröffentlichung war in IE9 im Jahr 2011.
gsnedders
Außerdem speichert Opera JS-Bytecode nicht nur über das Neuladen zwischen. (Generierter Maschinencode wird jedoch nicht zwischengespeichert).
Gsnedders
2
@ Jivings Nehmen Sie das oben genannte als Quelle. (Ich bin einer der Leute im Carakan-Team.)
Gsnedders
12

Opera macht es, wie in der anderen Antwort erwähnt. ( Quelle )

Firefox (SpiderMonkey-Engine) speichert keinen Bytecode zwischen. ( Quelle )

WebKit (Safari, Konqueror) speichert keinen Bytecode zwischen. ( Quelle )

Ich bin mir nicht sicher über IE [6/7/8] oder V8 (Chrome). Ich denke, IE führt möglicherweise eine Art Caching durch, während V8 dies möglicherweise nicht tut. IE ist eine geschlossene Quelle, daher bin ich mir nicht sicher, aber in V8 ist es möglicherweise nicht sinnvoll, "kompilierten" Code zwischenzuspeichern, da sie direkt in Maschinencode kompiliert werden.

cha0site
quelle
1
IE6–8 wird es mit ziemlicher Sicherheit nicht. IE9 könnte, aber ich habe keine Beweise so oder so. Kompiliertes JS wird wahrscheinlich nirgendwo zwischengespeichert, da es ziemlich oft ziemlich groß ist.
Gsnedders
@gsnedders: Ich bin mir nicht sicher, ob IE8 dies technisch nicht kann. Es scheint, dass es auch zu Bytecode kompiliert wird (nicht offiziell, aber geschlossen). Es gibt also keinen technischen Grund, dies nicht zwischenzuspeichern. IE9 scheint eine JIT hinzuzufügen, um sie in nativen Code zu kompilieren.
Cha0site
2
Bytecode wurde vom IE für ... für immer verwendet. Es ist nichts Neues in IE8. Es ist nur so, dass bei einem Dolmetscher die Leistung des Dolmetschers so viel langsamer ist als die Analysezeit, dass sie völlig irrelevant ist. IE9 verfügt über eine völlig neue JS-Engine (von Grund auf neu), sodass zwischen beiden nichts folgt.
Gsnedders
3

Soweit mir bekannt ist, speichert nur Opera das analysierte JavaScript zwischen. Siehe den Abschnitt "Zwischengespeicherte kompilierte Programme" hier .

gsnedders
quelle
danke, hast du auch mehr details zu anderen browserfamilien?
Ajreal
2

Es ist nichts wert, dass Google Dart dieses Problem explizit über "Snapshots" angeht. Ziel ist es, die Initialisierung und Ladezeit durch Laden der vorbereiteten Version des Codes zu beschleunigen.

InfoQ hat eine gute Beschreibung unter http://www.infoq.com/articles/google-dart

igrigorik
quelle
0

Ich denke, dass die richtige Antwort "nicht immer" wäre. Soweit ich weiß, spielen sowohl der Browser als auch der Server eine Rolle bei der Bestimmung, was zwischengespeichert wird. Wenn Sie wirklich jedes Mal Dateien neu laden müssen, sollten Sie dies meiner Meinung nach (z. B.) in Apache konfigurieren können. Natürlich könnte der Browser des Benutzers so konfiguriert werden, dass diese Einstellung ignoriert wird, aber das ist wahrscheinlich unwahrscheinlich.

Daher würde ich mir vorstellen, dass in den meisten praktischen Fällen die Javascript-Dateien selbst zwischengespeichert werden, aber jedes Mal, wenn die Seite geladen wird, dynamisch neu interpretiert werden.

Zachary Murray
quelle
0

Der Browser nutzt definitiv das Caching, aber ja, die Browser analysieren das JavaScript jedes Mal, wenn eine Seite aktualisiert wird. Denn wenn eine Seite vom Browser geladen wird, werden zwei Bäume erstellt: 1. Inhaltsbaum und 2. Renderbaum.

Dieser Renderbaum besteht aus Informationen zum visuellen Layout der dom-Elemente. Wenn also eine Seite geladen wird, wird das Javascript analysiert und alle dynamischen Änderungen durch das Javascript mögen das Positionieren des dom-Elements, das Ein- / Ausblenden des Elements und das Hinzufügen / Entfernen des Elements, was dazu führt, dass der Browser den Renderbaum neu erstellt. Aber die modernen Browser wie FF und Chrome gehen etwas anders damit um. Sie haben das Konzept des inkrementellen Renderns. Wenn also wie oben erwähnt dynamische Änderungen durch das js auftreten, werden diese Elemente nur gerendert und neu gestrichen.

Abhidev
quelle