如何增强ASP程序性能(3)

---摘自《天极网》
技巧11：使用Response Buffering
通过打开“response buffering”可以缓冲一个值得输出的整个页面内容，这将最小化输出到浏览器的数据量，从而提高了整体性能。每一次输出都耗费许多，所以写得越少，效果越好。TCP/IP在发送少量大的数据包时，要比发送大量小的数据包工作效率高，因为它是慢速启动并不断发送的。
有2种方法打开Response Buffering。首先，可以使用Internet Services Manager为整个应用程序打开response buffering，这是推荐的方式，而且在IIS4.0和IIS5.0中，默认状态下，response buffering是打开的。其次，在每一页面上，可以在头部放置如下代码开打开response buffering：
< % Response.Buffer = True % >
这段代码必须在任何数据输出到浏览器前被执行（就是说，在任何html内容显示前和在任何cookie被设置前）。通常情况下，为整个应用程序打开response buffering是很好的方案，这么做后就不用在每个页面头部设置如上的代码。
关于打开response buffering的一个通用问题是：用户必须要等待整个页面全部产生后，才能看到内容。对于一个长时间运行的页面来说，可以设置Response.Buffer=False关闭缓冲。然后，好的策略是利用Response.Flush方法，它将输出所有已被ASP描述的HTML内容到浏览器。比如，在描述了一个1，000行表格的100行后，ASP就可以使用Response.Flush来强迫输出这100行的内容到浏览器，这时用户就可以看到前100行数据，同时其余的行数据正在准备生成。
注意，关于上面的1，000行表格输出的例子，对于一些浏览器器来说，除非遇到< /table >标记，它们不会输出表格的任何内容。如果这样，可以将表格分割成许多含有少量行的多个表格，然后在每一个表格产生后，调用Response.Flush输出。新版的Internet Explorer在整个表格下载后才显示内容，并且，如果定义了表格的列宽度，生成表格的速度将特别快。
关于打开response buffering的另外一个问题是：当生成非常大的页面时，将消耗非常大的服务器内存。
技巧12：批处理单行脚本和Response.Write命令
VBScript语法< % = expression % >的意思是输出expression的数值。如果response buffering没有打开，每个这样的语句将按照许多小数据包的形式输出数据到浏览器，这将降低程序性能。因此，请使用下面的技巧：替换紧挨着的多个一行表达式调用为一个调用，用Response.Write名称输出。比如，在下面的例子中，对于每行每个字段的输出，只有一个写操作：

    <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>

下面是更有效率的代码，每行一个输出：

    <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>

当response buffering关闭时，这个技巧非常得有用。最好是打开response buffering，这样就可以看到批量的Response.Wwrite是如何提高了程序性能。
技巧13：使用< OBJECT >标记引用对象
如果需要引用除代码路径外的对象（尤其是服务器、Application范围的对象），请在Global.asa文件中使用
< object runat=server id=objname >标记来定义它们，而不要使用Server.CreateObject方法。使用Server.CreateObject方法可以立即创建对象，这样如果随后不使用它，就浪费了资源。使用
< object id=objname >标记可以定义对象objname，但是直到它的属性或者方法首次使用时，objname才实际创建。
技巧14：避免在循环中串联字符串
许多人在循环中建立一个字符串，就象下面的样子：

    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

这存在几个问题。首先是重复的连接字符串消耗二次方的时间，而且，运行的时间与计算的字段数量也是平方的关系。下面的简单例子更清楚地说明这一点：

    s = ""
    For i = Asc("A") to Asc("Z")
     s = s & Chr(i)
    Next

在第1层循环时，S的值是“A”；第2层循环时，VBScript要重新分配字符串，拷贝了2个字符（“AB”）到S中；第3层循环时，需要再重新分配并且拷贝3个字符到S中。在第N层循环时，就需要重新分配并拷贝N个字符到S中。那就是1+2+3+...+N的总和，也就是N*（N＋1）/2个拷贝。
在上面的记录集例子中，如果有100个记录和5个字段，内部循环就要执行100*5＝500次，并且，完成所有拷贝和再分配任务的时间将接近500*500＝250，000。这还是一个适当尺寸记录集的拷贝工作。
在这个例子中，可以通过替换字符串连接为Response.Write（）或者行内脚本（< % =fld.Value % >）的方法提高程序性能。如果response buffering打开（也应该打开），这将很快，因为Response.Write仅仅附加数据在缓冲区的尾部，而且不需要再分配。
如果用JScript连接字符串，强烈建议使用“＋＝”操作符，就是说，使用s＋＝“字符串”，而不是s ＝ s＋“字符串”。
技巧15：打开浏览器和代理的缓冲
默认情况下，ASP禁止了浏览器和代理的缓冲功能。如果有一个每次都不要更新的页面，就应该打开浏览器和代理的缓冲，这将允许浏览器和代理在一段时间内使用该页面的“缓冲”拷贝数据。缓冲能够大大地减轻服务器的数据转载量，并提高用户的浏览性能。
哪些类别的动态页面适合被缓存呢？下面是一些例子：

- 天气页面，每5分钟更新一次
- 新闻或版本列表页面，每天更新2次

注意：使用浏览器或者代理缓存后，对Web服务器的点击次数就会减少。如果想精确地了解所有页面，或者对于邮递广告，就不适于使用浏览器和代理缓存了。
浏览器缓存由HTTP“Expires”头参数控制，它由Web服务器发送给浏览器。ASP提供了2个简单的方法发送这个头部参数。设置页面在未来一定时间内到期，可以使用Response.Expires属性。下面的例子将告诉浏览器内容在10分钟后过期：
< % Response.Expires = 10 % >
设置Response.Expires为负数或者0，就禁止了缓存。对第2个属性Response.ExpiresAbsolute的设置，允许指定在一个特殊时间到来时内容过期。
< % Response.ExpiresAbsolute = #May 31,2001 13:30:15# % >
除了使用Response对象来设置到期时间，还可以在HTML文件头部写< META >标记。尽管代理不会注意到这个标记，但是一些浏览器可以。
< META HTTP-EQUIV="Expires" VALUE="May 31,2001 13:30:15" >
最后，对于HTTP代理，使用Response.CacheControl可以指示是否缓存内容。设置属性为“Public”，打开代理缓存内容的功能。
< % Response.CacheControl = "Public" % >
默认情况下，这个属性是设置成“Private”的。注意：不要让代理缓冲那些显示给特定用户的页面，因为代理可能会将属于其他用户的页面送给当前用户。