Das Aufkommen von AJAX hat die Funktionsweise von Webanwendungs-Clients stark verändert. Es ermöglicht Benutzern, sich auf ihre Arbeit zu konzentrieren, ohne sich mit lästigen Seitenaktualisierungen herumschlagen zu müssen. Theoretisch kann die AJAX-Technologie die Wartezeit für Benutzervorgänge erheblich verkürzen und den Datenverkehr im Netzwerk einsparen. Dies ist jedoch nicht immer der Fall. Benutzer beschweren sich häufig darüber, dass die Reaktionsgeschwindigkeit von Systemen, die AJAX verwenden, verringert ist.
Der Autor beschäftigt sich seit vielen Jahren mit der AJAX-Forschung und -Entwicklung und war an der Entwicklung von Dorado beteiligt, einer relativ ausgereiften AJAX-Plattform in China. Nach der Erfahrung des Autors ist AJAX nicht die Ursache für dieses Ergebnis. Oft wird die Verringerung der Systemreaktionsgeschwindigkeit durch unangemessenes Schnittstellendesign und unzureichend effiziente Programmiergewohnheiten verursacht. Im Folgenden analysieren wir einige Aspekte, auf die während des AJAX-Entwicklungsprozesses geachtet werden muss.
Richtiger Einsatz von Client-Programmierung und Remote-Prozeduraufrufen.
Die clientseitige Programmierung basiert hauptsächlich auf JavaScript. JavaScript ist eine interpretierte Programmiersprache und ihre Betriebseffizienz ist etwas geringer als die von Java. Gleichzeitig läuft JavaScript in einer streng eingeschränkten Umgebung wie dem Browser. Daher sollten Entwickler ein klares Verständnis davon haben, welche Logik auf der Clientseite ausgeführt werden kann.
Wie die clientseitige Programmierung in tatsächlichen Anwendungen eingesetzt werden sollte, hängt von der Erfahrung und dem Urteilsvermögen des Entwicklers ab. Viele Probleme hier können nur verstanden werden. Aufgrund des begrenzten Platzes fassen wir hier grob die folgenden Vorsichtsmaßnahmen zusammen:
Vermeiden Sie die häufige Verwendung von Remote-Prozeduraufrufen so weit wie möglich, vermeiden Sie beispielsweise die Verwendung von Remote-Prozeduraufrufen in Schleifenkörpern.
Wenn möglich, verwenden Sie den AJAX-Remoteprozeduraufruf (asynchroner Remoteprozeduraufruf).
Vermeiden Sie es, schwere Datenoperationen auf der Clientseite zu platzieren. Zum Beispiel: große Stapel von Datenkopiervorgängen, Berechnungen, die einen großen Datendurchlauf erfordern usw.
Verbessern Sie die Operationsmethode von DOM-Objekten.
Bei der clientseitigen Programmierung beanspruchen Vorgänge an DOM-Objekten häufig am ehesten CPU-Zeit. Bei der Bedienung von DOM-Objekten ist der Leistungsunterschied zwischen verschiedenen Programmiermethoden oft sehr groß.
Im Folgenden finden Sie drei Codeteile mit genau den gleichen Ergebnissen. Ihre Funktion besteht darin, eine 10x1000-Tabelle auf der Webseite zu erstellen. Allerdings sind ihre Laufgeschwindigkeiten sehr unterschiedlich.
/* Testcode 1 – Dauer: 41 Sekunden*/
var table = document.createElement("TABLE");
document.body.appendChild(table);
for(var i = 0; i < 1000; i++){
var row = table.insertRow(-1);
for(var j = 0; j < 10; j++){
var cell = objRow.insertCell(-1);
cell.innerText = "( " + i + " , " + j + " )";
}
}
/* Testcode 2 – Dauer: 7,6 Sekunden*/
var table = document.getElementById("TABLE");
document.body.appendChild(table);
var tbody = document.createElement("TBODY");
table.appendChild(tbody);
for(var i = 0; i < 1000; i++){
var row = document.createElement("TR");
tbody.appendChild(row);
for(var j = 0; j < 10; j++){
var cell = document.createElement("TD");
row.appendChild(cell);
cell.innerText = "( " + i + " , " + j + " )";
}
}
/* Testcode 3 – benötigte Zeit: 1,26 Sekunden*/
var tbody = document.createElement("TBODY");
for(var i = 0; i < 1000; i++){
var row = document.createElement("TR");
for(var j = 0; j < 10; j++){
var cell = document.createElement("TD");
cell.innerText = "( " + i + " , " + j + " )";
row.appendChild(cell);
}
tbody.appendChild(row);
}
var table = document.getElementById("TABLE");
table.appendChild(tbody);
document.body.appendChild(table);
Der Unterschied zwischen „Testcode 1“ und „Testcode 2“ besteht hier darin, dass beim Erstellen von Tabellenzellen unterschiedliche API-Methoden verwendet werden. Der Unterschied zwischen „Testcode 2“ und „Testcode 3“ liegt in der leicht unterschiedlichen Abarbeitungsreihenfolge.
Wir können einen so großen Leistungsunterschied zwischen „Testcode 1“ und „Testcode 2“ nicht analysieren. Derzeit ist bekannt, dass insertRow und insertCell tabellenspezifische APIs in DHTML sind und createElement und appendChild native APIs von W3C DOM sind. Ersteres sollte eine Kapselung des Letzteren sein. Allerdings können wir daraus nicht schließen, dass die native API des DOM immer besser ist als die objektspezifische API. Es wird empfohlen, einige grundlegende Leistungstests durchzuführen, wenn Sie eine API häufig aufrufen müssen.
Der Leistungsunterschied zwischen „Testcode 2“ und „Testcode 3“ ergibt sich hauptsächlich aus der unterschiedlichen Build-Reihenfolge. Der Ansatz von „Testcode 2“ besteht darin, zuerst das äußerste <TABLE>-Objekt zu erstellen und dann nacheinander <TR> und <TD> in der Schleife zu erstellen. Der Ansatz von „Testcode 3“ besteht darin, zunächst die gesamte Tabelle im Speicher von innen nach außen aufzubauen und sie dann der Webseite hinzuzufügen. Der Zweck besteht darin, die Anzahl der Neuberechnungen des Seitenlayouts durch den Browser so weit wie möglich zu reduzieren. Immer wenn wir einer Webseite ein Objekt hinzufügen, versucht der Browser, das Layout der Steuerelemente auf der Seite neu zu berechnen. Daher können wir zunächst das gesamte zu erstellende Objekt im Speicher erstellen und es dann sofort zur Webseite hinzufügen. Dann führt der Browser lediglich eine Neuberechnung des Layouts durch. Um es in einem Satz zusammenzufassen: Je später Sie appendChild ausführen, desto besser. Um die Betriebseffizienz zu verbessern, können wir manchmal sogar in Betracht ziehen, mit „removeChild“ das vorhandene Steuerelement von der Seite zu entfernen und es nach Abschluss der Erstellung wieder auf der Seite zu platzieren.
Verbessern Sie die Geschwindigkeit der Zeichenfolgenakkumulation. Wenn ich AJAX zum Übermitteln von Informationen verwende, muss ich möglicherweise häufig einige relativ große Zeichenfolgen zusammenstellen, um die POST-Übermittlung über XmlHttp abzuschließen. Obwohl die Übermittlung einer so großen Menge an Informationen unelegant erscheinen mag, müssen wir uns manchmal einem solchen Bedürfnis stellen. Wie schnell ist die Anhäufung von Zeichenfolgen in JavaScript? Lassen Sie uns zunächst das folgende Experiment durchführen. Akkumulieren Sie eine Zeichenfolge mit einer Länge von 30.000.
/* Testcode 1 – Dauer: 14,325 Sekunden*/
var str = "";
for (var i = 0; i < 50000; i++) {
str += "xxxxxx";
}
Dieser Code dauerte 14,325 Sekunden und die Ergebnisse waren nicht ideal. Jetzt ändern wir den Code in die folgende Form:
/* Testcode 2 – Dauer: 0,359 Sekunden*/
var str = "";
für (var i = 0; i < 100; i++) {
var sub = "";
für (var j = 0; j < 500; j++) {
sub += "xxxxxx";
}
str += sub;
}
Dieser Code dauert 0,359 Sekunden! Dasselbe Ergebnis, alles, was wir tun, ist, zuerst einige kleinere Saiten zusammenzusetzen und sie dann zu größeren Saiten zusammenzufügen. Dieser Ansatz kann die Menge der in den Speicher kopierten Daten in den späteren Phasen der String-Assemblierung effektiv reduzieren. Nachdem wir dieses Prinzip kennen, können wir den obigen Code zum Testen weiter zerlegen. Der folgende Code dauert nur 0,140 Sekunden.
/* Testcode 3 – Dauer: 0,140 Sekunden*/
var str = "";
für (var i1 = 0; i1 < 5; i1++) {
var str1 = "";
für (var i2 = 0; i2 < 10; i2++) {
var str2 = "";
für (var i3 = 0; i3 < 10; i3++) {
var str3 = "";
für (var i4 = 0; i4 < 10; i4++) {
var str4 = "";
für (var i5 = 0; i5 < 10; i5++) {
str4 += "xxxxxx";
}
str3 += str4;
}
str2 += str3;
}
str1 += str2;
}
str += str1;
}
Allerdings ist der obige Ansatz möglicherweise nicht der beste! Wenn die Informationen, die wir übermitteln müssen, im XML-Format vorliegen (tatsächlich können wir in den meisten Fällen versuchen, die zu übermittelnden Informationen im XML-Format zusammenzustellen), können wir auch einen effizienteren und eleganteren Weg finden – die Verwendung von DOM-Objekten zum Zusammenstellen Zeichen für uns string. Der folgende Absatz benötigt nur 0,890 Sekunden, um eine Zeichenfolge mit einer Länge von 950015 zusammenzusetzen.
/* Verwenden Sie DOM-Objekte, um Informationen zusammenzustellen – benötigte Zeit: 0,890 Sekunden*/
var xmlDoc;
if (browserType == BROWSER_IE) {
xmlDoc = new ActiveXObject("Msxml.DOMDocument");
}
anders {
xmlDoc = document.createElement("DOM");
}
var root = xmlDoc.createElement("root");
for (var i = 0; i < 50000; i++) {
var node = xmlDoc.createElement("data");
if (browserType == BROWSER_IE) {
node.text = "xxxxxx";
}
anders {
node.innerText = "xxxxxx";
}
root.appendChild(node);
}
xmlDoc.appendChild(root);
var str;
if (browserType == BROWSER_IE) {
str = xmlDoc.xml;
}
anders {
str = xmlDoc.innerHTML;
}
Vermeiden Sie Speicherlecks von DOM-Objekten.
Speicherlecks von DOM-Objekten im IE sind ein Problem, das von Entwicklern oft ignoriert wird. Die Konsequenzen, die es mit sich bringt, sind jedoch sehr schwerwiegend! Dies führt dazu, dass die Speichernutzung des IE weiter ansteigt und die Gesamtlaufgeschwindigkeit des Browsers deutlich langsamer wird. Bei einigen stark geleakten Webseiten wird die Laufgeschwindigkeit verdoppelt, auch wenn sie einige Male aktualisiert werden.
Zu den gebräuchlicheren Speicherleckmodellen gehören das „zyklische Referenzmodell“, das „Abschlussfunktionsmodell“ und das „DOM-Einfügereihenfolgemodell“. Wir können sie durch Dereferenzierung bei der Zerstörung der Webseite vermeiden. Was das „DOM-Einfügungsreihenfolgemodell“ betrifft, muss es vermieden werden, indem einige gängige Programmiergewohnheiten geändert werden.
Weitere Informationen zum Memory-Leak-Modell können schnell über Google gefunden werden, und dieser Artikel wird nicht zu sehr darauf eingehen. Hier empfehle ich Ihnen jedoch ein kleines Tool, mit dem Sie Speicherlecks auf Webseiten finden und analysieren können: Drip. Die aktuelle neuere Version ist 0.5 und die Download-Adresse lautet http://outofhanwell.com/ieleak/index.php
Segmentiertes Laden und Initialisieren komplexer Seiten. Für einige Schnittstellen im System, die sehr komplex und unpraktisch in der Verwendung von IFrame sind, können wir segmentiertes Laden implementieren. Beispielsweise können wir für eine mehrseitige Registerkartenoberfläche zunächst die Standardseite der mehrseitigen Registerkarte herunterladen und initialisieren und dann die AJAH-Technologie (asynchrones JavaScript und HTML) verwenden, um den Inhalt auf anderen Registerkartenseiten asynchron zu laden. Dadurch wird sichergestellt, dass die Oberfläche dem Benutzer überhaupt angezeigt werden kann. Verteilen Sie den Ladevorgang der gesamten komplexen Schnittstelle in den Betriebsprozess des Benutzers.
Verwenden Sie GZIP, um den Netzwerkverkehr zu komprimieren.
Zusätzlich zu den oben erwähnten Verbesserungen auf Codeebene können wir GZIP auch verwenden, um den Netzwerkverkehr effektiv zu reduzieren. Derzeit unterstützen bereits alle gängigen Mainstream-Browser den GZIP-Algorithmus. Zur Unterstützung von GZIP müssen wir oft nur wenig Code schreiben. In J2EE können wir beispielsweise den folgenden Code in Filter verwenden, um zu bestimmen, ob der Client-Browser den GZIP-Algorithmus unterstützt, und dann java.util.zip.GZIPOutputStream verwenden, um die GZIP-Ausgabe nach Bedarf zu implementieren.
/* Code zur Bestimmung, wie der Browser GZIP unterstützt*/
privater statischer String getGZIPEncoding(HttpServletRequest request) {
String AcceptEncoding = request.getHeader("Accept-Encoding");
if (acceptEncoding == null) return null;
AcceptEncoding = AcceptEncoding.toLowerCase();
if (acceptEncoding.indexOf("x-gzip") >= 0) return "x-gzip";
if (acceptEncoding.indexOf("gzip") >= 0) return "gzip";
null zurückgeben;
}
Im Allgemeinen kann die Komprimierungsrate von GZIP für HTML und JSP etwa 80 % erreichen, und der dadurch verursachte Leistungsverlust auf dem Server und Client ist nahezu vernachlässigbar. In Kombination mit anderen Faktoren können uns Websites, die GZIP unterstützen, 50 % des Netzwerkverkehrs einsparen. Daher kann die Verwendung von GZIP bei Anwendungen, bei denen die Netzwerkumgebung nicht besonders gut ist, erhebliche Leistungsverbesserungen bringen. Mit Fiddler, dem HTTP-Überwachungstool, können Sie ganz einfach die Menge der Kommunikationsdaten auf einer Webseite vor und nach der Verwendung von GZIP ermitteln. Die Download-Adresse von Fiddler lautet http://www.fiddlertool.com /fiddler/
Die Leistungsoptimierung von Webanwendungen ist tatsächlich ein sehr großes Thema. Aufgrund des begrenzten Platzes kann dieser Artikel nur einige Details abdecken und Ihnen auch nicht die Optimierungsmethoden dieser Details vollständig zeigen. Ich hoffe, dass dieser Artikel die Aufmerksamkeit aller auf Webanwendungen lenken kann, insbesondere auf die Optimierung der clientseitigen Leistung. Schließlich sind serverseitige Programmiertechniken seit vielen Jahren jedem bekannt und es gibt kaum Potenzial für die Leistungsausnutzung auf der Serverseite. Methodenverbesserungen auf der Clientseite können oft zu überraschenden Leistungsverbesserungen führen.