Vorwort
Ich glaube, jeder hat viele Themen zum Laden von JavaScript -Skript angetroffen. Hauptsächlich an mehreren Punkten -
1> Probleme mit Dateilade-, Dateiabhängigkeits- und Ausführungsreihenfolge, die durch synchrone Skripte und asynchrone Skripte verursacht werden
2> Probleme mit der Leistungsoptimierung durch synchrone Skripte und asynchrone Skripte
Ein tiefes Verständnis aller Aspekte der Skriptbelastung ist nicht nur der Lösung praktischer Probleme, sondern auch für das Greifen und Ausführen der Leistungsoptimierung förderlich.
Schauen Sie sich zunächst einen Skript -Tag -Code an -
Die Codekopie lautet wie folgt:
<script src = "js/myapp.js"> </script>
Wenn es auf <Head> platziert wird, blockiert es die gesamte Seitenwiedergabe, wodurch der Benutzer in einem "weißen Bildschirm des Todes" bleibt, bis das Skript geladen und ausgeführt wird. Das Skript am Ende von <body> lässt den Benutzer nur die statische Seite ohne Vitalität sehen. Wo das Rendering des Kunden mit ineffektiven Kontrollen und leeren Kisten verstreut sein soll. Nehmen Sie einen Testfall -
Die Codekopie lautet wie folgt:
<! DocType html>
<html>
<head Lang = "en">
<meta charset = "utf-8">
<title> asynchronisiertes Lade -Skript </title>
<script src = "js/test.js"> </script>
</head>
<body>
<Div> Ich bin zufrieden </div>
<img src = "img/test.jpg">
</body>
</html>
Unter ihnen der Inhalt in test.js -
Die Codekopie lautet wie folgt:
ALERT ('Ich bin der Skriptcode im Kopf. Nachdem die JS hier ausgeführt wurde, beginnt das Rendering des Körperinhaltes!');
Wir werden sehen, dass Alert ein Pausespunkt ist, und zu diesem Zeitpunkt ist die Seite leer. Beachten Sie jedoch, dass die gesamte Seite zu diesem Zeitpunkt geladen wurde. Wenn der Körper Tags für bestimmte SRC -Attribute (z. B. das IMG -Tag oben) enthält, hat der Browser zu diesem Zeitpunkt damit begonnen, den relevanten Inhalt zu laden. Kurz gesagt, es ist zu beachten, dass sich das Arbeitszeitpunkt des JS -Engine und der Rendering -Engine gegenseitig ausschließen (einige Bücher nennen es UI -Thread).
Daher benötigen wir, dass Skripte, die dafür verantwortlich sind, dass die Seite besser aussieht und besser verwendet wird, sofort geladen werden, und Skripte, die später geladen werden können, werden später geladen.
1. Verzögerung der Skriptausführung
Jetzt wird es immer beliebter, Skripte am Ende des Seite <body> Tag zu platzieren. Auf diese Weise kann der Benutzer einerseits die Seite schneller sehen, und andererseits kann das Skript die geladenen DOM -Elemente direkt bedienen. Dieses "Umzug" ist für die meisten Skripte eine enorme Verbesserung. Das Seitenmodell lautet wie folgt -
Die Codekopie lautet wie folgt:
<! DocType html>
<html>
<head Lang = "en">
<!-Metadaten und Drehbuchblätter gehen hier->
<script src = "headscript.js"> </script>
</head>
<body>
<!-Inhalt geht hier->
<script src = "bodyScript.js"> </script>
</body>
</html>
Dies beschleunigt die Renderzeit der Seite erheblich. Beachten Sie jedoch, dass dies den Benutzern die Möglichkeit gibt, mit der Seite zu interagieren, bevor Bodyscript geladen wird. Der Grund, warum der Browser die Skripte nicht laden kann, bevor das vollständige Dokument geladen wird, ist ein großer Engpass für große Dokumente, die über langsame Verbindungen übertragen werden.
Im Idealfall sollte das Laden des Skripts gleichzeitig mit dem Laden des Dokuments durchgeführt werden und wirkt sich nicht auf die Darstellung des DOM aus. Auf diese Weise kann das Skript ausgeführt werden, sobald das Dokument fertig ist, da das entsprechende Skript in der Reihenfolge des <Skript> -Tags geladen wurde.
Wir können diese Anforderung erfüllen, indem wir auf Verschiebung verwenden, dh.
Die Codekopie lautet wie folgt:
<script src = "deferredscript.js"> </script>
Das Hinzufügen des Defer -Attributs ist gleichbedeutend mit der Anweisung des Browsers: Bitte laden Sie dieses Skript sofort. Bitte warten Sie, bis das Dokument fertig ist und alle Skripte mit dem Defer -Attribut ausgeführt wurden, bevor Sie es ausgeführt haben.
Auf diese Weise bringt das Einlegen von Skripten von Verzögerungen in das Head -Tag alle Vorteile des Platzierens von Skripten auf das Body -Tag und kann die Ladegeschwindigkeit großer Dokumente erheblich verbessern. Der Seitenmodus zu diesem Zeitpunkt ist - -
Die Codekopie lautet wie folgt:
<! DocType html>
<html>
<head Lang = "en">
<!-Metadaten und Drehbuchblätter gehen hier->
<script src = "headscript.js"> </script>
<script src = "deferredscript.js" Defer> </script>
</head>
<body>
<!-Inhalt geht hier->
</body>
</html>
Allerdings unterstützen nicht alle Browser die Aufhebung (für einige moderne Browser werden ihre internen Skripte, wenn Defer deklariert wird, kein Dokument aus. Dies bedeutet, dass Sie den Code aller Verzögerungsskripte in einer Struktur wie JQuery's $ (Dokument). Dies lohnt sich, da fast 97% der Besucher die Vorteile einer parallelen Belastung genießen können, während weitere 3% der Besucher JavaScript mit vollem Funktionsumfang verwenden können.
2. Vollständige Parallelisierung von Skripten
Lassen Sie die Skripte einen Schritt schneller geladen und ausgeführt werden. Ich möchte nicht warten, bis die Defer -Skripte nacheinander ausgeführt werden (Defer erinnert uns an ein bestelltes Warteschlangenszenario, in dem das Dokument leise darauf wartet, dass das Dokument geladen wird), und ich möchte nicht warten, bis das Dokument vor dem Ausführen dieser Skripte fertig ist. Ich möchte diese Skripte so schnell wie möglich laden und ausführen. Hier denken wir an das asynchronisierte Attribut von HTML5, aber sind Sie sich bewusst, dass es sich um eine chaotische Anarchie handelt.
Zum Beispiel laden wir zwei völlig irrelevante Skripte von Drittanbietern, und die Seite läuft ohne sie gut und es ist mir egal, wer zuerst rennt und wer später rennt. Daher ist die Verwendung des asynchronen Attributs dieser Drittanbieter-Skripte der Verbesserung ihrer Laufgeschwindigkeit gleichbedeutend mit dem Ausgeben eines Cents.
Das asynchrische Attribut wird zu HTML5 neu hinzugefügt. Die Funktion ähnelt dem Aufschub, dh sie ermöglicht das Dom -Rendering beim Herunterladen von Skripten. Es wird jedoch so schnell wie möglich nach dem Herunterladen ausgeführt (d. H. Die JS -Engine ist untätig und sofort ausgeführt), und es gibt keine Garantie dafür, dass das Skript in der Reihenfolge ausgeführt wird. Sie werden vor dem Onload -Ereignis abgeschlossen sein.
Firefox 3.6, Opera 10.5, dh 9 und die neuesten Chrome und Safari unterstützen das asynchronisierte Attribut. Async und Defer können gleichzeitig verwendet werden, so dass alle IES nach dem IE 4 asynchrone Laden unterstützen, aber achten Sie darauf, dass Async aufschreibt.
Dann lautet das Seitenmodell zu diesem Zeitpunkt wie folgt -
Die Codekopie lautet wie folgt:
<! DocType html>
<html>
<head Lang = "en">
<!-Metadaten und Drehbuchblätter gehen hier->
<script src = "headscript.js"> </script>
<script src = "deferredscript.js" Defer> </script>
</head>
<body>
<!-Inhalt geht hier->
<script src = "asyncscript1.js" async defer> </script>
<script src = "asyncscript2.js" async defer> </script>
</body>
</html>
Achten Sie hier auf die Ausführungsreihenfolge - Jede Skriptdatei wird geladen, dann wird Headscript.js ausgeführt, und dann wird Defferedscript.js im Hintergrund während der DOM -Rendering geladen. Dann werden am Ende der Dom -Rendering defferedscript.js und die beiden asynchronen Skripte ausgeführt. Beachten Sie, dass diese beiden Skripte für Browser, die das asynchronisierte Attribut unterstützen, nicht in Ordnung sind.
A. Programmierbares Skriptladen
Obwohl die Funktionen der beiden oben genannten Skripteigenschaften sehr attraktiv sind, werden sie aufgrund von Kompatibilitätsproblemen nicht weit verbreitet. Daher verwenden wir Skripte, um andere Skripte mehr zu laden. Zum Beispiel möchten wir nur ein Skript für Benutzer laden, die bestimmte Bedingungen erfüllen, nämlich das oft erwähnte "faule Laden".
Auf der Browser -API -Ebene gibt es zwei vernünftige Möglichkeiten, Serverskripte zu kriechen und auszuführen -
1> AJAX -Anforderung erstellen und verwenden Sie die EV -Funktion, um die Antwort zu verarbeiten
2> Fügen Sie das <Skript> -Tag in das DOM ein
Die letztere Methode ist besser, da der Browser sich Sorgen macht, HTTP -Anfragen für uns zu generieren. Darüber hinaus hat Eval auch einige praktische Probleme: Auszugsumfang, Debugging ist chaotisch und kann auch die Leistung verringern. Wenn Sie ein Skript mit dem Namen feature.js laden möchten, sollten wir einen Code wie folgt verwenden:
Die Codekopie lautet wie folgt:
var head = document.getElementsByTagName ('head') [0];
var script = document.createelement ('script');
script.src = 'feature.js';
head.Appendchild (script);
Natürlich müssen wir uns mit Callback -Hören befassen, und die HTML5 -Spezifikation definiert eine Onload -Eigenschaft, die Rückrufe binden kann.
Die Codekopie lautet wie folgt:
script.onload = function () {
console.log ('Skript geladen ...');
}
IE8 und ältere Versionen unterstützen jedoch nicht Onload, sie unterstützen OnreadyStatechange. Darüber hinaus gibt es immer noch viele seltsame Dinge, die mit Fehlern umgehen müssen. Hier können Sie sich auf einige beliebte schulbasierte Ladebibliotheken wie LabJs, Yepnope, RefordeJs usw. verweisen.
Wie folgt, habe ich selbst eine einfache LoadJS -Datei zusammengefasst -
Die Codekopie lautet wie folgt:
var loadJS = Funktion (URL, Rückruf) {
var head = document.getElementsByTagName ('head') [0];
var script = document.createelement ('script');
script.src = url;
script.type = "text/javaScript";
head.Appendchild (script);
// Skript -Tag, es gibt eine OneReadyStatEchange -Veranstaltung unter dem IE, und es gibt ein Onload -Ereignis unter dem W3C -Standard
// IE9+ unterstützt auch den W3C -Standard
var ua = navigator.useragent,
ua_version;
// IE6/7/8
if (/msie ([^;]+)/. test (ua)) {
ua_version = parsefloat (regexp ["$ 1"], 10);
if (ua_version <= 8) {
script.onReadyStatechange = function () {
if (this.readystate == "geladen") {
callback ();
}
}
} anders {
script.onload = function () {
callback ();
};
}
} anders {
script.onload = function () {
callback ();
};
}
};
Ich werde nicht über das asynchrone Laden von Skripten in Dokument.Write sprechen. Jetzt tun dies nur wenige Menschen, weil die Browserunterschiede wirklich überwältigend sind.
Beachten Sie, dass der JS -Code im Inneren nicht ausgeführt wird, wenn JS -Code asynchron vorliegt, um JS -Dateien vorzuladen.
Lassen Sie uns schließlich über das asynchrone Ladeskript in RefordeJs sprechen.
RequiredJS garantiert nicht, dass die Zielskripte nacheinander ausgeführt werden, sondern stellt nur sicher, dass ihre laufende Reihenfolge ihre jeweiligen Abhängigkeitsanforderungen erfüllen kann. Daher stellen wir sicher, dass alle Skripte so bald wie möglich parallel geladen werden und sie in geordneter Weise gemäß der Abhängigkeitstopologie ausführen.
4. Zusammenfassung
OK, wenn es darum geht, ist die Aussage des asynchronen Ladeskripts vorbei. Lassen Sie mich hier noch einmal über die Optimierungsreihenfolge sprechen -
1> Auf die traditionelle Weise verwenden wir Skript -Tags, um sie direkt in HTML -Dokumente einzubetten. Hier sind zwei Situationen -
A> in das Kopf -Tag eingebettet - Achten Sie darauf, dass dies nicht das parallele Laden anderer statischer Ressourcendateien im Dokumentinhalt beeinflusst. Es wirkt sich auf die Darstellung des Dokumentinhalts aus, dh die DOM -Rendering zu diesem Zeitpunkt wird blockiert und der weiße Bildschirm wird präsentiert.
B> Einbettet am unteren Rand des Körper -Tags - Um das Phänomen des weißen Bildschirms zu vermeiden, geben wir Vorrang vor der Rendern des DOM und der Ausführung des Skripts, aber das Problem kommt erneut. Lassen Sie uns zuerst über die erste Frage sprechen - wenn der Inhalt des DOM -Dokuments relativ groß ist, wird sich die Interaktionsereignisbindung verzögert und die Erfahrung wird etwas schlechter sein. Natürlich müssen wir wichtige Skripte basierend auf den Bedürfnissen zuerst ausführen. Lassen Sie uns über das zweite Problem sprechen - da die Skriptdateien bis zum Ende des Körpers liegen, wird das Laden dieser Skripte im Vergleich zu den Skripten im Kopf verzögert. Daher ist es nicht der Endpunkt der Optimierung.
C> Defer -Attribut hinzufügen - Wir hoffen, dass das Skript so schnell wie möglich parallel geladen wird, und wir werden diese Skripte immer noch in den Kopf legen. Das Laden des Skripts sollte gleichzeitig mit dem Laden des Dokuments durchgeführt werden und wirkt sich nicht auf die Darstellung des DOM aus. Auf diese Weise kann das Skript ausgeführt werden, sobald das Dokument fertig ist. Es gibt also ein Scheinattribut. Achten Sie jedoch auf seine Kompatibilität. Für Browser, die das Defer -Attribut nicht unterstützen, müssen wir den Code in einem $ (dokument). Es ist zu beachten, dass alle Skripte mit Aufschubattributen nach ihrer Erscheinungsreihenfolge nacheinander ausgeführt werden, sodass sie auch streng synchronisiert sind.
2> Der vorherige Punkt handelt von synchronen Ausführungsskripten (beachten Sie, dass der Ladevorgang dieser Skripte parallel ist, aber der Unterschied zwischen der Anforderung zuerst und wer dann die Anfrage auslöst). Der nächste Optimierungspunkt sind "parallele Ausführungsskripte". Natürlich wissen wir, dass zu einem Zeitpunkt nur eine JS -Datei ausgeführt wird. Das "Parallel" hier bedeutet, dass jeder, der zuerst lädt,, solange der JS -Engine zu diesem Zeitpunkt untätig ist, sofort ausgeführt wird. Die Optimierung hier ist in zwei Typen unterteilt -
A> Hinzufügen der asynchronen Eigenschaft - Sie kann tatsächlich den oben erwähnten Optimierungspunkt vervollständigen, aber es hat hohe Einschränkungen, dh nur für das Laden von Skripts ohne Abhängigkeit. Das am besten geeignete Beispiel ist die Einführung mehrerer Drittanbieter-Skripte. Auch die Kombination mit dem Deffer -Attribut ist wirklich eine große Sache. Natürlich hat es auch Kompatibilitätsprobleme. Die obigen drei Probleme haben zu ihrer seltenen Anwendung geführt. Bei der Verwendung von Async müssen Sie auf Abhängigkeitsprobleme genau beachtet werden.
B> Skriptladen Skripte - Natürlich verwenden wir dies, um den Zweck der "parallelen Ausführung von Skripten" zu erreichen. Gleichzeitig erleichtern wir auch die Kontrolle über Skriptabhängigkeiten, sodass wir eine intelligente Lastverwaltung für asynchrones Laden in Anforderungswesen verwenden.
Ok, das ist alles.
Hier spreche ich nur über den Inhalt im Zusammenhang mit asynchronen Ladeskripten. Es gibt einen weiteren Teil des Inhalts, der asynchrones Laden von Stildateien oder anderen statischen Ressourcen ist. fortgesetzt werden......