Fifteen ASP Tips to Improve Performance and Style

Nancy Winnick Cluts

October 8, 1997

Introduction

If you are anything like me, you probably enjoy tinkering with the latest technology. Staying on that bleeding edge can be a great kick, but it can also leave you scratching your head. You may have come up with something totally cool for your Web site—but since no other Web site has the feature, you end up wondering where to get help.

The Site Builder Web site is a lot like that. We try to use as much of the newest technology as possible. This makes our Web site very innovative, but it can also (sometimes) make it slow. Like you, we are always looking for ways to improve the performance of our Web pages and to improve our coding style. Recently, we were lucky enough to get some great suggestions from people on the Internet Information Server (IIS) team, including ways to improve our Active Server Pages (ASP) performance and style tips. The suggestions listed in this article have been tested on http://home.microsoft.com, and have been very successful. And if you choose to only follow one or two of the listed tips, follow Tip 1 and Tip 9. The combination of these two tips caused the most significant speed improvement (twice as fast) on http://home.microsoft.com. So, if you need to be judicious about your time and effort (and who doesn't?), implement Tips 1 and 9.

Tip 1. Use GLOBAL.ASA for Application Level Files

Instead of using the ASP FileSystemObject to read files on a page, load the file(s) into an application-level array in Global.asa. Global.asa is an optional file in which you can specify event scripts and declare objects that have session or application scope. Global.asa is not displayed to users but stores application-global event information and objects. Then use your page to reference the application-level array with the data in it. This means the read from the file happens once per server instead of once per page per user. You can run a separate .asp file to refresh the contents of the application-level array. You may also want to consider using the Dictionary object (see Tip 9). Remember, if you want to speed things up, this tip gives you the greatest bang for the buck.

Confused about how to implement this?

If you are a script developer, you have to use the FileSystemObject to read files into an array or into a Dictionary object. Something that might not immediately occur to you is to read files in your Global.asa file and to put the array (the one you are reading the files into) or the Dictionary object into Application state. This lets users access the information in the array or Dictionary object without having to retrieve the information each time via an .asp file request.

I know what you're thinking: "But what if the cached content needs to be updated? I bet I can't use it then!" Wrong. You can. If the contents of the cached information need to change, you can call into an Administrator-access-only .asp file containing script that can do an Application.Lock command, update the cached information in the array or Dictionary object, and finally do an Application.Unlock command.

Tip 2. Remove HTML Comments from Production Code

That's right. If it was hard to write, it should be hard to understand. Only kidding—but it does seem that if you remove all HTML comments (script comments are fine), large sections of HTML text can be block copied to the client. As a result, your script will run faster on IIS 3.0. (Under IIS 4.0, HTML comments no longer cause performance degradation.) Of course, for your own edification (and to keep code maintenance from being a nightmare) you might want to keep a special README file containing notes on what you did and why—or you might want to consider keeping comments in any place where the code seems "obscure." You can also keep a copy of your source code with the comments and strip the comments out of a separate copy for production. This way, you can keep your comments to yourself.

In production of applications that use C or C++ code, developers generally maintain source code that can be compiled into two versions: the debug version and the retail version. Most tools for creating applications using C++, such as Microsoft Visual C++, have this functionality built in. This would be a nice addition to HTML tools.

Tip 3. Batch Response.Write Statements

If you use the <%=…%> syntax to write in multiple places in your code, consider "batching" those writes by replacing multiple, interspersed <%=…%> writes with one Response.Write statement. While you are making that change, take a look at how you have your HTML code with regard to your script. Try not to intersperse HTML and script too much; instead, try to have blocks of script and blocks of HTML.

Tip 4. Instantiate Objects Using the <OBJECT> Tag

If you need to refer to objects that may not be used, instantiate them by using the <OBJECT> tag rather than using Server.CreateObject. Using Server.CreateObject causes the object to be created immediately. If you don't use that object later, you end up wasting resources.

Tip 5. Use Local Variables Whenever Possible

Local variables are variables that reside within subroutines and functions (this is known as local scope). These variables are compiled into numeric references and put in a table. Local variable references can be resolved at compile time. Global variables are resolved at run time. This means that local-variable access is many times faster than global-variable access. Also, undimensioned global variables are the slowest of all—the first time an undimensioned global variable is used, the entire object model is searched for an object with that named property before a new one is created.

Here's an example of some fairly common code:

Foo.bar.blah.baz = Foo.bar.blah.qaz(1)
If Foo.bar.blah.zaq = Foo.bar.blah.abc then

When this code runs, here's what happens:

  1. The variable Foo is resolved as a global object.

  2. The variable bar is resolved globally as a member of Foo.

  3. The variable blah is resolved globally as a member of Foo.bar.

  4. The variable qaz is resolved globally as a member of foo.bar.blah.

  5. Invoke Foo.bar.blah.qaz(1).

  6. Do steps 1 through 3 again. The system does not know if the call to qaz changed the object model, so steps 1 through 3 must be done again to resolve baz.

  7. Resolve baz as a member of Foo.bar.blah. Do the property put.

  8. Do steps 1 through 3 again and resolve zaq.

  9. Do steps 1 through 3 yet another time and resolve abc.

As you can see, this is terribly inefficient (and way slow). The fast way to write this code in Microsoft® Visual Basic® Scripting Edition (VBScript) is:

Set myobj = Foo.bar.blah ' do the resolution of blah ONCE
Myobj.baz = myobj.qaz(1)
If Myobj.zaq = Myobj.abc then

Tip 6. Avoid Redimensioning Arrays

While we're on the subject of Dim: try to avoid redimensioning arrays. As far as performance is concerned, if you have a machine that is constrained by physical memory size, it's much better to set the initial dimension of the array in its worst-case scenario—or to set the dimension to its optimal case and redim as necessary. This does not mean that you should just go out and allocate a couple of Mg of memory if you know you aren't going to need it.

The code below shows gratuitous use of Dim and Redim.

<% 
dim MyArray()
Redim MyArrray(2)
MyArray(0) = "hello"
MyArray(1) = "good-bye"
.
.
.

some other code where you end up needing

more space happens, then ...

Redim Preserve  MyArray(5)
MyArray(2) = "more stuff"
MyArray(3) = "even more stuff"
MyArray(4) = "yet more stuff"
%>

It is far better to simply Dim the array to the correct size (in this case 5) initially, then Redim the array to make it larger. You may waste a little memory (if you don't end up using all of the elements), but you will gain speed.

Tip 7. Avoid "Public" Variables

Don't use variables defined as Public. If you are writing VBScript or accessing variables in your ActiveX™ control or Java applet, avoid using Public variables. The Public keyword is currently being investigated for future use, and because Public doesn't buy you anything, it's better to use Dim.

Tip 8. Use Literal Paths

Try to avoid MapPath if at all possible. Instead, use the literal path if you know it. Using MapPath requires IIS to retrieve the current server path, which means a special request to IIS—which in turn means (you guessed it) decreased performance.

Tip 9. Use the "Dictionary" Object

The VBScript-provided Dictionary object provides fast look up and storage of arbitrary key-data pairs. The Dictionary object gives you access to items in the array by key, so it is faster to find things that aren't contiguous in memory (because you are specifying the key that you are using rather than having to know where in the array the object resides). If you have nonlinear key data that you need to search, it will be faster using the Dictionary object.

However, in the spirit of not throwing out the baby with the bath water, arrays provide a much faster lookup and storage of key-data pairs that are contiguous in memory. It is also important to note that indexing a dictionary is slower than indexing an array. You should choose the data structure that works best for you.

Tip 10. Take Advantage of Your Browser's Validation Abilities

If you are running a smart browser, the browser is capable of doing some validation for you. Take advantage of this whenever you can. Then, perform validation via your scripting. When all else fails, then you can go ahead and access your database on the back end. But remember, whenever you access that database that lives on the server, you are going to take a performance hit. This can be very expensive if you have several values in a form that you are validating. If you know that you will need to run some script on the client side, go ahead and move the code to the client side for faster performance. When you are running on the client, you have the processor(s) for your use; the server has to use its processing power for all of the requests it receives.

Another idea: If you are using a form that employs server-side scripting and has lots of conditional input, move that conditional code to the client's scripting engine—for example, VBScript or JScript™. While this makes server code faster by skipping a browsecap and a conditional, it does send over-the-wire code that isn't necessarily needed. With a small script, this is probably a good choice. For bigger scripts, it might not be useful.

Tip 11. Avoid Using Server Variables

Accessing server variables causes your Web site to make a special request to the server and collect all server variables, not just the one that you requested. This is akin to needing to retrieve a specific item in a folder that you have in that musty attic of yours. When you want that one item, you have to go to the attic to get the folder before you can access the item. This is the same thing that happens when you request a server variable: the performance hit occurs the first time you request a server variable. Subsequent requests for other server variables do not cause a performance hit.

Tip 12. Turn ON Option Explicit

Turn on the Option Explicit option in your .asp file. Unlike C, Visual Basic allows you to use variables without explicitly declaring them. Turning on this option helps to identify undefined variables—you will get an error message for undefined variables. Turning on Option Explicit makes undeclared local variables illegal. Undeclared local variables are as slow as global variables (about twice as slow as declared local variables). Turning on this option will help you find these slugs so that you can get them out of your code.

Tip 13. Copy Collections Values to Local Variables

If there are collections values that you are using repeatedly, copy these values onto the client in the form of local variables. This saves you a look-up operation on the collection each time you use the value, and it will speed up your script.

Tip 14. Be Careful of the Session Object

You can use the Session object to store information that you may need for a particular user-session. Variables that are stored in the Session object are not discarded when the user jumps between pages in the application; instead, these variables persist for the entire user session. The Web server automatically creates a Session object when a Web page from the application is requested by a user who does not already have a session. The server destroys the Session object when the session expires or is abandoned. To avoid this, you can turn off the Session feature; however, the Session feature can't be turned off on a per-application basis in IIS 3.0. Turning it off for the entire server is faster but drops a lot of functionality. Instead, be very careful to use the Session object only when you really need to.

If you use the Session object at all in your application, be sure to use it as soon as possible in order to avoid the Session object from being reset. In IIS 4.0, the session state can be enabled on a per-application basis and it can be disabled for specified .asp files.

Tip 15. Do Performance Testing

Yeah, you already knew this—but I feel bad about telling you to scrap your HTML comments, and this is one way to redeem myself. Performance test your ASP-based applications. This will help you to keep an eye on performance and, of course, will prove that you have "style." Don't wait until you get the weekly "Slow as a slug" award for Web sites. Instead, run performance tests when you make significant changes to your .asp files. Heck, since you're already testing all of your changes integrally (aren't you?), why not add a performance test to your daily testing?