ASP Tipp 11: Verwenden Sie lokale Variablen in Subroutinen und Funktionen

Bei lokalen Variablen handelt es sich um Variablen, die in Subroutinen und Funktionen deklariert wurden. In einer Funktion oder Subroutine ist der Zugriff auf lokale Variablen schneller als der Zugriff auf globale Variablen. Durch lokale Variablen ist Code außerdem übersichtlicher. Daher sollten Sie diese, wenn möglich, verwenden.

 

ASP Tipp 12: Kopieren Sie häufig verwendete Daten in Skriptvariablen

Beim Zugriff auf COM-Objekte in ASP sollten Sie häufig verwendete Objektdaten in Skriptvariablen kopieren. Dadurch werden die im Vergleich zum Zugriff auf Skriptvariablen relativ kostspieligen COM-Methodenaufrufe reduziert. Beim Zugreifen auf Collection- und Dictionary-Objekte reduziert diese Methode außerdem teure Suchen.

Wenn Sie mehrmals auf Objektdaten zugreifen, sollten Sie sie im Allgemeinen in einer Skriptvariablen ablegen. Request-Variablen (Form- oder QueryString-Variablen) sind für diese Optimierung ideal. Ihre Site gibt z. B. eine QueryString-Variable namens UserID weiter. Angenommen auf diese UserID wird auf einer bestimmten Seite ein Dutzend Mal verwiesen. Weisen Sie die UserID am oberen Rand der ASP-Seite einer Variablen zu, anstatt Request(„UserID“) ein Dutzend Mal aufzurufen, und verwenden Sie diese Variable dann überall auf der Seite. Damit sparen Sie 11 COM-Methodenaufrufe.

In der Praxis kann der Zugriff auf COM-Eigenschaften und -Methoden unerwartet kostspielig sein. Das folgende Beispiel enthält (syntaktisch gesprochen) ziemlich gängigen Code:

Foo.bar.blah.baz = Foo.bar.blah.qaz(1)

If Foo.bar.blah.zaq = Foo.bar.blah.abc Then ‚ …

Beim Ausführen des Codes geschieht Folgendes:

  1. Die Variable Foo wird als globales Objekt aufgelöst.
  2. Die Variable bar wird als Mitglied von Foo aufgelöst. Dies ist ein COM-Methodenaufruf.
  3. Die Variable blah wird als Mitglied von Foo.bar aufgelöst und ist ebenfalls ein COM-Methodenaufruf.
  4. Die Variable qaz wird als Mitglied von foo.bar.blah aufgelöst, und dies ist ebenfalls ein COM-Methodenaufruf.
  5. Rufen Sie Foo.bar.blah.quaz(1) auf. Es wird ein weiterer COM-Methodenaufruf ausgeführt. Alles klar?
  6. Wiederholen Sie Schritt 1 bis 3, um baz aufzulösen. Das System weiß nicht, ob das Objektmodell durch den Aufruf von qaz geändert wurde. Deshalb müssen die Schritte 1 bis 3 wiederholt werden, um baz aufzulösen.
  7. Lösen Sie baz als Mitglied von Foo.bar.blah auf. Fähren Sie die Eigenschafteneingabe aus.
  8. Wiederholen Sie Schritt 1 bis 3, um zaq aufzulösen.
  9. Wiederholen Sie Schritt 1 bis 3, um abc aufzulösen.

Wie Sie sehen, ist dies unheimlich ineffizient (und langsam). Um diesen Code schnell in VBScript zu schreiben, verwenden Sie Folgendes:

Set myobj = Foo.bar.blah ‚ do the resolution of blah ONCE

Myobj.baz = myobj.qaz(1)

If Myobj.zaq = Myobj.abc Then ‚…

Wenn Sie VBScript 5.0 oder höher verwenden, können Sie beim Schreiben die With-Anweisung verwenden.

With Foo.bar.blah

.baz = .qaz(1)

If .zaq = .abc Then ‚…

End With

Dieser Tipp gilt auch für das Programmieren mit VB.

ASP Tipp 13: Vermeiden das Neudimensionieren von Arrays

Vermeiden Sie nach Möglichkeit das Neudimensionieren von Arrays mit Redim. Wenn die physikalische Speichergröße Ihres Computer eingeschränkt ist, empfiehlt es sich in Bezug auf die Leistung, die Anfangsdimension des Arrays auf das schlimmste Szenario festzulegen. Sie können die Dimension auch für das optimale Szenario einstellen und bei Bedarf neu festlegen. Dies bedeutet nicht, dass Sie einfach ein paar Megabyte Arbeitsspeicher zuordnen sollen, wenn Sie wissen, dass er nicht gebraucht wird.

Dieser Code zeigt den unnötigen Gebrauch von Dim und Redim.

<%

Dim MyArray()

Redim MyArray(2)

MyArray(0) = „hello“

MyArray(1) = „good-bye“

MyArray(2) = „farewell“

‚ some other code where you end up needing more space happens, then …

Redim Preserve MyArray(5)

MyArray(3) = „more stuff“

MyArray(4) = „even more stuff“

MyArray(5) = „yet more stuff“

%>

Es ist wesentlich besser, das Feld anfangs mit Dim auf die richtige Größe einzustellen (in diesem Fall 5), und es dann mit Redim zu vergrößern. Dabei verschwenden Sie eventuell etwas Speicher (wenn Sie nicht alle Elemente verwenden), gewinnen aber an Geschwindigkeit.

ASP Tipp 14: Verwenden Sie den Antwortpuffer

Sie können eine ganze auszugebende Seite durch Aktivieren des „Antwortpuffers“ puffern. Dadurch wird die Anzahl der Schreibvorgänge im Browser reduziert und die Gesamtleistung gesteigert. Für jeden Schreibvorgang ist ein großer Aufwand nötig (sowohl in IIS und bezüglich der über die Leitung gesendeten Datenmengen), d. h. je weniger Leitungen, desto besser. TCP/IP funktioniert aufgrund seines langsamen Starts und der Nagling-Algorithmen (zum Minimieren von Netzwerkstaus) effizienter, wenn anstelle von vielen kleinen Datenblöcken wenige große Datenblöcke gesendet werden können.

Sie können den Antwortpuffer auf zwei Arten aktivieren. Einerseits können Sie den Antwortpuffer mit dem Internetdienste-Manager für die gesamte Anwendung aktivieren. Diese Methode wird empfohlen. Der Antwortpuffer wird in IIS 4.0 und IIS 5.0 standardmäßig für neue ASP-Anwendungen aktiviert. Andererseits können Sie den Antwortpuffer auf Seitenbasis aktivieren, indem Sie folgende Codezeile am oberen Rand der ASP-Seite positionieren.

<% Response.Buffer = True %>

Diese Codezeile muss ausgeführt werden, bevor Antwortdaten in den Browser geschrieben werden (d. h., bevor HTML im ASP-Skript angezeigt wird, und bevor Cookies mit der Response.Cookies-Auflistung festgelegt wurden). Im Allgemeinen sollten Sie den Antwortpuffer für die ganze Anwendung aktivieren. Damit ist die obige Codezeile auf jeder Seite überflüssig.

Response.Flush

Benutzer sind häufig der Meinung, dass die Antwortzeit von ASP-Seiten durch den Antwortpuffer langsamer ist (obwohl die Antwortzeit insgesamt verbessert ist), weil sie warten müssen, bis die gesamte Seite generiert wurde, bevor eine Anzeige erfolgt. Sie können den Antwortpuffer für lange Seiten deaktivieren, indem Sie Response.Buffer = False festlegen. Es gibt aber eine bessere Strategie: Verwenden Sie stattdessen die Response.Flush-Methode, bei der ASP den gesamten gezeichneten HTML-Inhalt im Browser anzeigt. Nachdem z. B. 100 Zeilen einer aus 1000 Zeilen bestehenden Tabelle gezeichnet wurden, kann ASP Response.Flush aufrufen, um die gezeichneten Ergebnisse im Browser anzuzeigen. Damit kann der Benutzer die ersten 100 Zeilen sehen, bevor die verbleibenden Zeilen fertig sind. Diese Methode bietet Ihnen das Beste aus beiden Bereichen: den Antwortpuffer in Kombination mit der allmählichen Präsentation der Daten im Browser.

(Beachten Sie, dass viele Browser beim oben dargestellten Beispiel einer aus 1000 Zeilen bestehenden Tabelle die Tabelle erst anzeigen, wenn sie das schließende Kennzeichen </table> sehen. Präfen Sie, ob die gewünschten Browser die teilweise Anzeige unterstützen. Sie können dieses Problem umgehen, indem Sie die Tabelle in mehrere Tabellen mit einer geringeren Anzahl von Zeilen aufteilen und nach jeder Tabelle Response.Flush aufrufen. Neuere Versionen von Internet Explorer zeigen Tabellen an, bevor sie vollständig gedownloadet wurden, und die Anzeige erfolgt besonders schnell, wenn sie die Spaltenbreiten der Tabelle festlegen. Dadurch braucht Internet Explorer die Spaltenbreiten nicht durch Messen des Inhalts jeder einzelnen Zelle zu berechnen.)  

Benutzer beschweren sich beim Antwortpuffer außerdem darüber, dass er beim Generieren sehr großer Seiten sehr viel Serverspeicher verbraucht. Ohne hier Weisheiten über das Generieren von sehr großen Seiten abzugeben, lässt sich dieses Problem ebenfalls mithilfe von Response.Flush beheben.

 

ASP Tipp 15: Stapeln Sie Inlineskripts und Response.Write-Anweisungen

Die VBScript-Syntax <% = expression %> schreibt die Werte von „expression“ in den ASP-Ausgabestrom. Wenn der Antwortpuffer nicht aktiviert ist, schreiben alle diese Anweisungen Daten in vielen kleinen Paketen über das Netzwerk in den Browser. Dies geht nur langsam vonstatten. Außerdem führt das Abwechseln von kleinen Skript- und HTML-Mengen zu einem Wechsel zwischen dem Skriptmodul und HTML, was sich ebenfalls negativ auf die Leistung auswirkt. Halten Sie sich daher an folgenden Tipp: Ersetzen Sie eng gepackte Inlineanweisungen durch einen Aufruf von Response.Write. Im folgenden Beispiel erfolgt pro Feld und Zeile ein Schreibvorgang im Antwortstrom, und pro Zeile finden viele Wechsel zwischen VBScript und HTML statt.

<table>

<% For Each fld in rs.Fields %>

<th><% = fld.Name %></th>

<%

Next

While Not rs.EOF

%>

<tr>

<% For Each fld in rs.Fields %>

<td><% = fld.Value %></td>

<% Next

</tr>

<% rs.MoveNext

Wend %>

</table>

Im effizienteren Code weiter unten erfolgt pro Zeile ein Schreibvorgang im Antwortstrom. Der gesamte Code ist in einem VBScript-Block enthalten:

<table>

<%

For each fld in rs.Fields

Response.Write („<th>“ & fld.Name & „</th>“ & vbCrLf)

Next

While Not rs.EOF

Response.Write („<tr>“)

For Each fld in rs.Fields %>

Response.Write(„<td>“ & fld.Value & „</td>“ & vbCrLf)

Next

Response.Write „</tr>“

Wend

%>

</table>

Dieser Tipp hat wesentlich stärkere Auswirkungen, wenn der Antwortpuffer deaktiviert ist. Es empfiehlt sich, den Antwortpuffer zu aktivieren, und auszuprobieren, ob die Leistung durch Stapelverarbeitung von Response.Write verbessert werden kann.

(In diesem speziellen Beispiel kann die verschachtelte Schleife, die den Tabellenkörper erstellt (While Not rs.EOF…), durch einen gut durchdachten Aufruf von GetString), ersetzt werden.)

ASP Tipp 16: Vermeiden Sie lange Wartezeiten durch Verwendung von Response.IsClientConnected

Wenn Benutzer ungeduldig werden, brechen sie Ihre ASP-Seite möglicherweise ab, bevor Sie mit dem Ausführen ihrer Anfrage beginnen können. Wenn sie auf Aktualisieren klicken oder auf Ihrem Server auf eine andere Seite wechseln, befindet sich eine neue Anfrage am Ende der ASP-Anfragewarteschlange und eine abgetrennte Anfrage in der Mitte der Warteschlange. Dies geschieht häufig bei einem stark belasteten Server (die Anfragewarteschlange ist in diesem Fall sehr lang und bringt ebenso lange Antwortzeiten mit sich) und führt zu einer Verschlimmerung der Situation. Es ergibt keinen Sinn, eine ASP-Seite (und insbesondere eine langsame, umfangreiche ASP-Seite) auszuführen, wenn der Benutzer nicht mehr verbunden ist. Sie können dies mit der Response.IsClientConnected-Eigenschaft überprüfen. Wenn sie False zurückgibt, sollten Sie Response.End aufrufen und den Rest der Seite abbrechen. Dieses Verhalten ist in IIS 5.0 im Code enthalten, d. h. wenn ASP im Begriff ist, eine neue Anfrage auszuführen, prüft es zuerst, wie lange die Anfrage sich schon in der Warteschlange befindet. Befindet sie sich schon seit mehr als 3 Sekunden in der Warteschlange, prüft ASP, ob der Client noch angeschlossen ist und bricht die Anfrage sofort ab, wenn dies nicht der Fall ist. Sie können diese Zeitüberschreibung in der Metabasis mit der AspQueueConnectionTestTime-Einstellung ändern.  

Bei einer Seite, deren Ausführung sehr lange dauert, sollten Sie außerdem Response.IsClientConnected in regelmäßigen Abständen prüfen. Wenn der Antwortpuffer aktiviert ist, empfiehlt es sich, Response.Flush in regelmäßigen Abständen auszuführen, damit der Benutzer den Eindruck hat, dass etwas passiert.

Anmerkung In IIS 4.0 funktioniert Response.IsClientConnected nicht ordnungsgemää, wenn Sie nicht zuerst eineResponse.Write-Anweisung ausführen. Wenn der Antwortpuffer aktiviert ist, können Sie auch eine Response.Flush-Anweisung ausführen. In IIS 5.0 ist dies nicht nötigt; Response.IsClientConnected funktioniert problemlos. Response.IsClientConnected ist in jedem Fall mit einigen Kosten verbunden. Verwenden Sie diese Anweisung daher nur vor einem Vorgang, der mindestens 500 Millisekunden dauert (das ist eine lange Zeit, wenn Sie versuchen, einen Durchsatz von mehreren Dutzenden von Seiten pro Sekunde zu erreichen). Als Faustregel gilt, diese Anweisung nicht bei jeder Wiederholung einer engen Schleife, wie z. B. beim Zeichnen der Zeilen einer Tabelle, sondern sie eher alle 20 oder 50 Tabellenzeilen aufzurufen.

ASP Tipp 17: Erstellen Sie Objekte mit dem „OBJECT“-Kennzeichen

Wenn Sie auf Objekte verweisen müssen, die möglicherweise nicht in allen Codepfaden verwendet wurden (insbesondere Objekte im Gültigkeitsbereich des Session- oder Application-Objekts), deklarieren Sie diese mit dem Kennzeichen <object runat=server id=objname> in der Datei Global.asa, anstatt die Server.CreateObject-Methode zu verwenden. Server.CreateObject erstellt das Objekt sofort. Wenn das Objekt später nicht verwendet wird, verschwenden Sie damit Ressourcen. Das Kennzeichen <object id=objname> deklariert objname, aber objname wird erst erstellt, wenn eine seiner Methoden oder Eigenschaften zum ersten Mal verwendet werden.

Dies ist ein anderes Beispiel für eine verzögerte Auswertung.

 

ASP Tipp 18: Verwenden Sie die TypeLib-Bindung mit ADO- und anderen Komponenten

Beim Verwenden von ADO nehmen Entwickler oft adovbs.txt auf, um auf die verschiedenen Konstanten von ADO zugreifen zu können. Diese Datei muss auf jeder Seite hinzugefügt werden, die die Konstanten verwenden möchte. Sie ist verhältnismäßig umfangreich und erhöht den Aufwand bei der Kompilierungszeit und Skriptgröße jeder ASP-Seite.

In IIS 5.0 gibt es erstmals die Möglichkeit der Bindung an die Typbibliothek einer Komponente. Dadurch können Sie einmal auf die Typbibliothek verweisen und sie auf jeder ASP-Seite verwenden, ohne dass alle Seiten unter der Kompilierung der Konstantendatei leiden, und Entwickler brauchen keine VBScript #include-Dateien für ASP zu erstellen.

Positionieren Sie folgende Anweisungen in der Datei Global.asa, um auf die ADO-TypeLib zuzugreifen.

<!– METADATA NAME=„Microsoft ActiveX Data Objects 2.5 Library“

TYPE=„TypeLib“ UUID=„{00000205-0000-0010-8000-00AA006D2EA4}“ –>

oder

<!– METADATA TYPE=„TypeLib“

FILE=„C:\Program Files\Common Files\system\ado\msado15.dll“ –>

ASP Tipp 19: Profitieren Sie von den Gültigkeitsfunktionen Ihres Browsers

Moderne Browser verfügen über erweiterte Unterstützung für Funktionen wie XML, DHTML, Java-Applets und Remote Data Service. Nutzen Sie die Vorteile dieser Funktionen wann immer möglich. Alle diese Technologien sparen Anfragen beim und Antworten durch den Webserver, denn sie nehmen eine Überprüfung des Clients sowie das Zwischenspeichern von Daten vor. Wenn Sie einen intelligenten Browser verwenden, kann dieser einen Teil der Überprüfung für Sie übernehmen (und z. B. prüfen, ob eine Kreditkarte über eine gültige Prüfsumme verfügt, bevor POST ausgeführt wird). Nutzen Sie auch dies wann immer möglich. Durch Reduzieren der Client-Server-Anfragen werden die Belastung des Webservers und der Netzwerkverkehr verringert (obwohl die erste an den Browser gesendete Seite möglicherweise umfangreicher ist) sowie die Back-End-Ressourcen, auf die der Server zugreift, reduziert. Darüber hinaus muss der Benutzer neue Seiten nicht mehr so häufig abrufen und macht somit positivere Erfahrungen. Dies bedeutet aber nicht, dass eine Überprüfung auf dem Server unnötig ist. Sie sollten diese auf jeden Fall immer durchführen, denn sie schätzt vor schädlichen Daten, die aus irgendeinem Grund (z. B. von Hackern) vom Client oder von Browsern gesendet werden, die keine Überprüfung des Clients durchführen.

Es wurde viel Wind um die Erstellung von „browserunabhängigem“ HTML-Code gemacht. Dieses Anliegen hält Entwickler häufig davon ab, sich gängige Browserfunktionen zu Nutze zu machen, die sich günstig auf die Leistung auswirken können. Für echte Hochleistungssites, bei denen die Browserreichweite eine Rolle spielt, empfiehlt es sich, Seiten für die gängigen Browser zu optimieren. Browserfunktionen lassen sich in ASP einfach mit der Komponente für Browserfähigkeiten feststellen. Programme, wie z. B. Microsoft FrontPage, sind beim Entwerfen von Code behilflich, der sowohl für die Browser als auch die HTML-Versionen funktioniert. Weitere Informationen finden Sie im Artikel „When is Better Worse? Weighing the Technology Trade-Offs“.

 

ASP Tipp 20: Vermeiden Sie die Zeichenfolgenverkettung in Schleifen

Viele Benutzer erstellen eine Zeichenfolge in einer Schleife wie folgt:

s = „<table>“ & vbCrLf

For Each fld in rs.Fields

s = s & „<th>“ & fld.Name & „</th>“

Next

While Not rs.EOF

s = s & vbCrLf & „<tr>“

For Each fld in rs.Fields

s = s & „<td>“ & fld.Value & „</td>“

Next

s = s & „</tr>“

rs.MoveNext

Wend

s = s & vbCrLf & „</table>“ & vbCrLf

Response.Write s

Bei dieser Methode gibt es mehrere Probleme. Als Erstes wird beim wiederholten Verketten von Zeichenfolgen quadratische Zeit gebraucht, d. h. die Zeit zum Ausführen dieser Schleife ist proportional zum Quadrat der Anzahl der Datensätze mal der Anzahl der Felder. Ein einfacheres Beispiel müsste dies deutlich machen.

s = „“

For i = Asc(„A“) to Asc(„Z“)

s = s & Chr(i)

Next

Bei der ersten Wiederholung erhalten Sie eine aus einem Zeichen bestehende Zeichenfolge, „A“. Bei der zweiten Wiederholung muss VBScript die Zeichenfolge neu zuweisen und zwei Zeichen („AB“) nach s kopieren. Bei der dritten Wiederholung muss s erneut zugewiesen und drei Zeichen nach s kopiert werden. Bei der Nten (26.) Wiederholung müssen N Zeichen neu zugewiesen und nach s kopiert werden. Dies ergibt eine Summe von 1+2+3+…+N und entspricht N*(N+1)/2 Kopiervorgängen.

Im oben dargestellten Beispiel für ein Recordset würde die innere Schleife bei 100 Datensätzen und 5 Feldern 100*5 = 500 mal ausgeführt werden, und die für alle Kopiervorgänge und Neuzuweisungen benötigte Zeit wäre proportional zu 500*500 = 250,000. Das sind für ein Recordset von mäßiger Größe recht viele Kopiervorgänge.

In diesem Beispiel könnte der Code verbessert werden, wenn die Zeichenfolgenverkettung durch Response.Write() oder Inlineskript (<% = fld.Value %>) ersetzt würde. Wenn der Antwortpuffer (wie empfohlen) aktiviert wird, ist dieser Code schnell, da Response.Write die Daten einfach am Ende des Antwortpuffers anhängt. Hierbei ist keine Neuzuweisung notwendig, und der Code ist sehr effizient.

In dem Sonderfall beim Transformieren eines ADO-Recordsets in eine HTML-Tabelle sollten Sie die Verwendung von GetRows oder GetString in Betracht ziehen.

Wenn Sie Zeichenfolgen in JScript verketten, wird dringend empfohlen, dass Sie den +=-Operator verwenden, d. h. verwenden Sie s += „some string“, und nicht s = s + „some string“.