### 如何增强 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”的。注意：不要让代理缓冲那些显示给特定用户的页面，因为代理可能会将属于其他用户的页面送给当前用户。