Ein wichtiger Teil des Entwicklungszyklus von Microsoft ist die Anpassung der Produktleistung. Auch die Leistungsoptimierung ist einer der Schlüsselbereiche, auf die Entwickler achten sollten. Nach Jahren der Entwicklung hat die Branche viel darüber gelernt, wie die Leistung von Win32-Programmen optimiert werden kann.
Eines der Probleme, mit denen Entwickler heute konfrontiert sind, besteht darin, dass sie nicht ganz verstehen, warum DTHML- und HTML-Seiten schnell oder langsam ausgeführt werden. Natürlich gibt es einige einfache Lösungen – zum Beispiel, keine 2-MB-Bilder zu verwenden. Wir haben einige andere interessante Techniken verwendet, um die Leistung von DHTML-Seiten zu verbessern. Wir hoffen, dass sie Ihnen dabei helfen können, die Leistung Ihrer eigenen Seiten zu verbessern.
Hier verwende ich ein Beispiel eines Programms zum Erstellen einer Tabelle. Mit den Methoden document.createElement() und element.insertBefore() wird eine Tabelle mit 1000 Zeilen (Row) erstellt. Jede Zeile hat eine Spalte (Zelle). Der in der Zelle enthaltene Inhalt wird als „Text“ bezeichnet. Wie schlimm könnte dieser Code sein? Wie viel Spielraum für Anpassungen hat ein so kleines Programm? Bitte beachten Sie die Einleitung.
Zu Beginn habe ich ein Programm geschrieben, von dem ich dachte, dass es schnell sein würde. Ich habe versucht, einige Probleme auf niedriger Ebene zu vermeiden, z. B. die nicht explizite Definition von Variablen oder die gleichzeitige Verwendung von VBScript und JavaScript auf einer Seite. Das Programm lautet wie folgt:
<html>
<Körper>
<Skript>
var tbl, tbody, tr, td, text, i, max;
max = 1000;
tbl = document.createElement("TABLE");
tbl.border = "1";
tbody = document.createElement("TBODY");
tbl.insertBefore(tbody, null);
document.body.insertBefore(tbl, null);
für (i=0; i<max; i++) {
tr = document.createElement("TR");
td = document.createElement("TD");
text = document.createTextNode("Text");
td.insertBefore(text, null);
tr.insertBefore(td, null);
tbody.insertBefore(tr, null);
}
</script>
</body>
</html>
Führen Sie dieses Programm auf einem PII233/64 MB Speicher/NT4.0/IE5.0-Computer aus. Die Seite wird von diesem Computer geladen. Die Zeit vom Beginn des Ladens der Seite bis zum vollständigen Beruhigen der Seite (alle Ereignisse wurden ausgeführt und die Bildschirmanzeige ist abgeschlossen) beträgt 2328 Millisekunden, was auch die Basis dieses Tests ist (ich nenne ihn Test1).
Auf dieser Seite besteht ein sehr zeitaufwändiger Vorgang darin, häufig auf globale Objekte wie „Dokument“, „Körper“, „Fenster“ usw. zu verweisen. Der Verweis auf alle diese ähnlichen globalen Variablen ist weitaus teurer als der Verweis auf eine einzelne lokale Variable.
Also habe ich den ersten Verbesserungsversuch gemacht: document.body in die lokale Variable „theBody“ zwischenspeichern:
folgenden Code hinzugefügt:
var theBody = document.body;
Ändern Sie dann diese Zeile:
document.body.insertBefore(tbl, null);
Ändern Sie es in:
theBody.insertBefore(tbl, null);
Sehen Sie sich das zweite Beispiel an.
Diese Änderung hatte keinen großen Einfluss auf die Gesamtzeit, sie verkürzte nur 3 ms. Es hat sich jedoch gezeigt, dass die Vorteile erheblich sind, wenn sich auch ein document.body-Objekt in der Schleife befindet und dessen Referenz geändert wird.
Anschließend habe ich das Dokumentobjekt zwischengespeichert – in unserem Test wurde das Dokumentobjekt insgesamt 3002 Mal referenziert. Der geänderte Code lautet wie folgt:
<html>
<Körper>
<Skript>
var tbl, tbody, tr, td, text, i, max;
max = 1000;
var theDoc = document;
var theBody = theDoc.body;
tbl = theDoc.createElement("TABLE");
tbl.border = "1";
tbody = theDoc.createElement("TBODY");
tbl.insertBefore(tbody, null);
theBody.insertBefore(tbl, null);
für (i=0; i<max; i++) {
tr = theDoc.createElement("TR");
td = theDoc.createElement("TD");
text = theDoc.createTextNode("Text");
td.insertBefore(text, null);
tr.insertBefore(td, null);
tbody.insertBefore(tr, null);
}
</script>
</body>
</html>
Sehen Sie sich das dritte Beispiel an.
Diese Laufzeit beträgt nur 2100 ms, was einer Zeitersparnis von etwa 10 % entspricht. Die Verwendung lokaler Variablen anstelle der direkten Referenzierung des Dokumentobjekts sparte jedes Mal durchschnittlich 0,4 Millisekunden.
Eine gängige Methode zur Leistungsoptimierung besteht darin, das „defer“-Attribut im <SCRIPT>-Tag festzulegen, wenn das Skript nicht sofort ausgeführt werden muss. (Das unmittelbare Skript ist nicht in einem Funktionsblock enthalten, daher wird es während des Ladevorgangs ausgeführt.) Nach dem Festlegen des „defer“-Attributs muss IE nicht darauf warten, dass das Skript geladen und ausgeführt wird. Dadurch wird die Seite schneller geladen. Im Allgemeinen bedeutet dies auch, dass unmittelbare Skripte am besten in Funktionsblöcken platziert werden und die Funktion im Onload-Handler des Dokuments oder Body-Objekts abwickeln. Diese Eigenschaft ist nützlich, wenn einige Skripts basierend auf Benutzeraktionen ausgeführt werden müssen, z. B. dem Klicken auf eine Schaltfläche oder dem Bewegen der Maus in einen bestimmten Bereich. Wenn jedoch einige Skripts während oder nach dem Laden der Seite ausgeführt werden müssen, sind die Vorteile der Verwendung des Defer-Attributs nicht groß.
Das Folgende ist die geänderte Version des Codes, der das Defer-Attribut verwendet:
<html>
<body onload="init()">
<script defer>
Funktion init() {
var tbl, tbody, tr, td, text, i, max;
max = 1000;
var theDoc = document;
var theBody = theDoc.body;
tbl = theDoc.createElement("TABLE");
tbl.border = "1";
tbody = theDoc.createElement("TBODY");
tbl.insertBefore(tbody, null);
theBody.insertBefore(tbl, null);
für (i=0; i<max; i++) {
tr = theDoc.createElement("TR");
td = theDoc.createElement("TD");
text = theDoc.createTextNode("Text");
td.insertBefore(text, null);
tr.insertBefore(td, null);
tbody.insertBefore(tr, null);
}
}
</script>
</body>
</html>
Sehen Sie sich das vierte Beispiel an.
Die Zeit dieses Tests beträgt 2043 ms. Dies ist eine Steigerung von 12 % gegenüber dem Basistest und 2,5 % mehr als beim vorherigen Test.
Eine Verbesserungsmethode, über die wir weiter unten sprechen, ist natürlich sehr nützlich, aber etwas mühsamer. Wenn Sie ein Element erstellen und es dann in eine baumartige Struktur einfügen müssen, ist es effizienter, es direkt in den Stamm einzufügen, anstatt es zuerst in einen großen Teilbaum und dann den großen Teilbaum in den Stamm einzufügen. Wenn Sie beispielsweise eine Tabelle mit einer Spalte in jeder Zeile und etwas Text in der Spalte erstellen, können Sie Folgendes tun:
1. <TR> erstellen
2. <TD> erstellen
3. TextNode-Knoten erstellen
4. TextNode in <TD einfügen >
5. <TD> in <TR> einfügen.
6. <TR> in TBODY einfügen.
Wenn es langsamer ist als die folgende Methode:
1. <TR> erstellen.
2. <TD> erstellen.
3. TextNode erstellen
. 4. <TR> einfügen Einfügen in TBODY
5. Einfügen von <TD> in <TR>
6. Einfügen von TextNode in <TD>
Die vier oben genannten Tests verwenden alle die erstere Methode. Für den fünften Test haben wir die letztgenannte Methode verwendet. Der Code lautet wie folgt:
<html>
<body onload="init()">
<script defer>
Funktion init() {
var tbl, tbody, tr, td, text, i, max;
max = 1000;
var theDoc = document;
var theBody = theDoc.body;
tbl = theDoc.createElement("TABLE");
tbl.border = "1";
tbody = theDoc.createElement("TBODY");
tbl.insertBefore(tbody, null);
theBody.insertBefore(tbl, null);
für (i=0; i<max; i++) {
tr = theDoc.createElement("TR");
td = theDoc.createElement("TD");
text = theDoc.createTextNode("Text");
tbody.insertBefore(tr, null);
tr.insertBefore(td, null);
td.insertBefore(text, null);
}
}
</script>
</body>
</html>
Sehen Sie sich das fünfte Beispiel an.
Test5 dauert nur 1649 ms. Dies ist eine Verbesserung von 25 % gegenüber dem letzten Test und fast 30 % schneller als der Ausgangswert.
Nachfolgende Änderungen wurden mithilfe vorgefertigter Stylesheets vorgenommen. Die Spaltenbreite einer Tabelle, die ein vorgefertigtes Stylesheet verwendet oder über das <COL>-Tag festgelegt wird. Wenn kein <COL>-Tag vorhanden ist, ist die Breite jeder Spalte gleichmäßig verteilt. Da die Größe jeder Spalte usw. nicht neu berechnet werden muss, verbessert die Verwendung eines Stylesheets tatsächlich die Leistung, insbesondere wenn die Anzahl der Spalten in der Tabelle groß ist.
Der Code zum Hinzufügen eines Stylesheets (CSS) ist sehr einfach und lautet wie folgt:
tbl.style.tableLayout = "fixed";
Sehen Sie sich das sechste Beispiel an.
Da die Tabelle in unserem Test nur eine Spalte hatte, verbesserte diese Änderung die Seitenleistung nur um 1,6 %. Bei mehr Spalten ist die Leistungssteigerung noch größer.
Die letzten beiden Tests haben die Art und Weise geändert, wie Text in die Tabelle eingefügt wird. In den vorherigen Tests haben wir zunächst einen TextNode erstellt und ihn dann in das TD eingefügt. In Test7 geben wir stattdessen den enthaltenen Text über innerText an. Der geänderte Code lautet:
td.innerText = "Text";
Sehen Sie sich das siebte Beispiel an.
Überraschenderweise war der Unterschied, den diese Modifikation bewirkte, enorm – eine Leistungsverbesserung von 9 % gegenüber dem letzten Mal und insgesamt 36 % Leistungsverbesserung gegenüber dem Original. Die Zeitspanne reicht von den ersten 2323 ms bis zu den letzten 1473 ms.
Mittlerweile weiß fast jeder, dass die Verwendung von element.innerHTML sehr langsam ist. Um zu sehen, wie langsam es ist, habe ich einen letzten Test durchgeführt: Text mithilfe von innerHTML anstelle von innerText eingefügt. Dadurch wird die Leistung stark reduziert. Die Zeit erreichte 3375 ms, was 80 % langsamer war als beim letzten Test und 45 % langsamer als beim Basistest. Offensichtlich ist innerHTML sehr zeitaufwändig.
Das Optimieren der Leistung von HTML-Seiten ähnelt dem Optimieren der Leistung von Win32-Anwendungen. Sie müssen wissen, was langsam und was schnell ist. Ich hoffe, dass diese Methoden Ihnen helfen können, die Seitenleistung zu verbessern.