ASP代码优化

对于ASP的初学者来说,最重要的是如何用 ASP 实现所需的功能。而对于那些已经入门,成功地将传统的C/S模式转为B/S模式的人来说,他们则关心如何才能使代码更有效,而不仅仅满足于实现了某个功能。代码优化,涉及到很多方面:数据库设计,数据访问方法,程序设计,对ASP掌握的熟练程度等等。可以说,对各种知识掌握的程度,决定了代码优化所能达到的程度。需要特别说明的是:优化的代码并非是运行最快的代码(通常情况下是)。速度只是衡量代码好坏的标准之一。优化的过程是各种标准综合权衡的过程。不过,本文讨论更多的是速度,因为它最直观。

 

本文分三部分:代码优化,数据访问优化,系统优化。代码优化包括组件的使用,包含文件的使用等等。

1. 不要在 Application 和 Session 中存储对象。
请看如下代码:
globe.asa
<SCRIPT LANGUAGE=VBScript RUNAT=Server>
Sub Application_OnStart
  Application("ConnectString") = "driver={SQL Server};server=.;uid=sa;pwd=;database=pubs"
End Sub
Sub Session_OnStart
  On Error Resume Next
  Dim cnn
  Set cnn = Server.CreateObject("ADODB.Connection")
  Cnn.Open Application("ConnectString")
  Session("connectObj") = cnn
End Sub
......
......
Dim rs
Set rs = Server.CreateObject("ADODB.RecordSet")
strSQL = "SELECT * FROM Authors ORDER BY au_lname"
rs.Open strSQL,Session("ConnectObj")
.....
这是有开发 C/S 系统经验的初学者常犯的错误,他的理由是:"我过去开发 C/S 系统时,对数据库来说一个 client 就是一个连接,类似 ASP 里的 Session。所以,把 Connection 对象放在 Session 中,会加快对数据库的访问。"
真的是这样吗?
把 Connection 对象放在 Session 中会引起一系列问题:资源的争用和消耗。( 参见文章: 组件,线程, ASP的性能 ) 应将对象从 Session 中清理出去,在页面级创建和释放对象。

2. 把常用的数据存放在 Application 中
假设你用 ASP 实现调查表的功能,其中有一项是让用户从城市的下拉列表中选择城市名,对于这种经常使用而且相对稳定的数据应将它放在 Application 中。通常会在 Application_OnStart 中进行初始化。不过,有时我们可能没有权限使用 global.asa ,没关系,可以采用下面的代码:
Dim var
var = Application("var")
If var = "" Then
  var = GetFrequentlyUsedData()      '函数GetFrequentlyUsedData()返回常用的数据,比如城市名称。
  Application.Lock
  Application("var") = var
  Application.Unlock
End If
更好的方法是存储 HTML 格式的数据。假设上面的函数GetFrequentlyUsedData()以数组的形式返回城市名称。我们可以这样做:
Dim var
Dim s
Dim intLoop,intMax
var = Application("var")
If var = "" Then
  var = GetFrequentlyUsedData()      '函数GetFrequentlyUsedData()返回常用的数据,比如城市名称。
  s = "<SELECT NAME=city>" & vbCrlf
  intMax = UBound(var)
  For intLoop = 0 To intMax
    s = s & "<OPTION>" & var[intLoop] & "</OPTION>" & vbCrlf
  Next
  s = s & "</SELECT>"
  Application.Lock
  Application("var") = s
  Application.Unlock
End If
特别强调的一点就是这种方法只适用于少量数据,否则会使服务器的性能大大下降。另外,谨防恶意使用 Application 变量的人。
我们经常把数据库连接字符串存储在 Application 中,这是个好方法,好就好在能保证每次与数据库连接时使用完全相同的连接条件,这是连接重用的前提。( 参见文章: 让数据库的连接更有效 ) 在下一篇中,我会再次讲到有关数据库连接的问题。

3. 把大数据存放在 Web Server 的磁盘上。
从后台数据库检索数据通常比从文件中检索要快,这只是对于请求一次页面来说,在点击次数很大的情况下,由于将数据保存在本地文件中,从而减轻了数据库服务器的负担,性能反而比从数据库检索好。
典型的例子就是用 ADO 的 Save 方法将结果集存储在本地。

4. 把 HTML 标记改为 Response.Write 成批输出。
效果会怎样呢?我们可以测试一下。
代码1
<HTML>
<HEAD>
<TITLE>Test</TITLE>
</HEAD>
<BODY>
<H1>Test</H1>
<%
Dim rs
Dim strSQL
Dim cnn
Set cnn = Server.CreateObject("ADODB.Connection")
cnn.Open "provider=sqloledb;data source=.;initial catalog=pubs;user id=sa;password=;"
Set rs = Server.CreateObject("ADODB.Recordset")
strSQL = "SELECT * FROM Authors ORDER BY au_lname"
rs.Open strSQL,cnn
%>
<TABLE BORDER=1>
  <TR>
    <TD><B>au_id</B></TD>
    <TD><B>au_lname</B></TD>
    <TD><B>au_fname</B></TD>
    <TD><B>phone</B></TD>
    <TD><B>address</B></TD>
    <TD><B>city</B></TD>
    <TD><B>state</B></TD>
    <TD><B>zip</B></TD>
  </TR>
<%
Do While not rs.Eof
%>
  <TR>
    <TD><%=rs("au_id")%></TD>
    <TD><%=rs("au_lname")%></TD>
    <TD><%=rs("au_fname")%></TD>
    <TD><%=rs("phone")%></TD>
    <TD><%=rs("address")%></TD>
    <TD><%=rs("city")%></TD>
    <TD><%=rs("state")%></TD>
    <TD><%=rs("zip")%></TD>
  </TR>
<%
rs.MoveNext
Loop
%>
</TABLE>
</BODY>
</HTML>
Click! 测试上面的代码 (注意:此代码从数据库中检索数据,如果是第一次连接,测试时间会长些。多测试几遍,取其稳定值。)

代码2
<%
Response.Write "<HTML><HEAD><TITLE>Test</TITLE>" &_
    "</HEAD><BODY><H1>Test</H1>"
Dim rs
Dim strSQL
Dim cnn
Set cnn = Server.CreateObject("ADODB.Connection")
cnn.Open "provider=sqloledb;data source=.;initial catalog=pubs;user id=sa;password=;"
Set rs = Server.CreateObject("ADODB.Recordset")
strSQL = "SELECT * FROM Authors ORDER BY au_lname"
rs.Open strSQL,cnn
Response.Write "<TABLE BORDER=1><TR><TD><B>au_id</B></TD><TD><B>au_lname</B></TD>" &_
    "<TD><B>au_fname</B></TD><TD><B>phone</B></TD><TD><B>address</B></TD>" &_
    "<TD><B>city</B></TD><TD><B>state</B></TD><TD><B>zip</B></TD></TR>"
Do While not rs.Eof
  Response.Write "<TR><TD>" & rs("au_id") & "</TD><TD>" & rs("au_lname") & "</TD>" &_
    "<TD>" & rs("au_fname") & "</TD><TD>" & rs("phone") & "</TD>" &_
    "<TD>" & rs("address") & "</TD><TD>" & rs("city") & "</TD>" &_
    "<TD>" & rs("state") & "</TD><TD>" & rs("zip") & "</TD>"
  rs.MoveNext
Loop
rs.Close
Set rs = Nothing
cnn.Close
Set cnn = Nothing
Response.Write "</TABLE></BODY></HTML>"
%>
Click! 测试上面的代码 (注意:此代码从数据库中检索数据,如果是第一次连接,测试时间会长些。多测试几遍,取其稳定值。)
有答案了吗?在我的机器上测试,用 HTML 标记的代码(代码1)需要 60~70ms,用 Response.Write 的代码(代码2)需要 40~50ms。
用 WAST 测试,结果分别为 TTLB:63.11ms 和 TTLB:47.50ms。

5. 不要在循环中连接字符串
<%
Dim str
str = "<HTML><HEAD><TITLE>Test</TITLE>" &_
    "</HEAD><BODY><H1>Test</H1>"
Dim rs
Dim strSQL
Dim cnn
Set cnn = Server.CreateObject("ADODB.Connection")
cnn.Open "provider=sqloledb;data source=.;initial catalog=pubs;user id=sa;password=;"
Set rs = Server.CreateObject("ADODB.Recordset")
strSQL = "SELECT * FROM Authors ORDER BY au_lname"
rs.Open strSQL,cnn
str = str & "<TABLE BORDER=1><TR><TD><B>au_id</B></TD><TD><B>au_lname</B></TD>" &_
    "<TD><B>au_fname</B></TD><TD><B>phone</B></TD><TD><B>address</B></TD>" &_
    "<TD><B>city</B></TD><TD><B>state</B></TD><TD><B>zip</B></TD></TR>"
Do While not rs.Eof
  str = str & "<TR><TD>" & rs("au_id") & "</TD><TD>" & rs("au_lname") & "</TD>" &_
    "<TD>" & rs("au_fname") & "</TD><TD>" & rs("phone") & "</TD>" &_
    "<TD>" & rs("address") & "</TD><TD>" & rs("city") & "</TD>" &_
    "<TD>" & rs("state") & "</TD><TD>" & rs("zip") & "</TD>"
  rs.MoveNext
Loop
rs.Close
Set rs = Nothing
cnn.Close
Set cnn = Nothing
str = str & "</TABLE></BODY></HTML>"
Response.Write str
Click! 测试上面的代码 (注意:此代码从数据库中检索数据,如果是第一次连接,测试时间会长些。多测试几遍,取其稳定值。)
WAST 测试结果:TTLB:90.95。

6. 利用 Response.Buffer = True,让缓存提高 ASP 的效率。
当使用缓存时,服务器在处理完整个页面后,才把页面内容发往浏览器。利用缓存,可以提高 ASP 的性能。如果关闭缓存,ASP 需要等待客户端的 TCP 确认,这使性能下降,尤其是在网速很低的情况下。如果你的页面比较复杂,处理起来很耗时的话,用户可能以为浏览器没有了反映,这时,请使用 Response.Flush。
在代码2中加入 Response.Buffer = True,然后再测试一下。
Click! 测试代码 (注意:此代码从数据库中检索数据,如果是第一次连接,测试时间会长些。多测试几遍,取其稳定值。)
WAST 测试结果:TTLB:39.72。
在 IIS 5.0 中,使用缓存是缺省的设置。

7. 注释行对性能几乎无影响,给代码加上注释是编程的良好习惯。
接下来,我在代码中加入了200行的注释,看看注释对性能有什么影响。
Click! 测试代码 (注意:此代码从数据库中检索数据,如果是第一次连接,测试时间会长些。多测试几遍,取其稳定值。)
实验结果:TTLB:40.21。

8. 适度使用包含文件
使用包含文件对速度有影响,但包含文件也有诸多优点:共享代码,易于维护等等。在速度和可维护性,可扩展性之间进行权衡,而不要一味的强调某一方面,才能正确的使用包含文件。( 参见文章:包含文件的得与失 )。

9. 重复引用 COM Object 属性时,把它存储在变量中进行引用。
slower:
If rs.RecordCount = 0 Then
  ......
Else
  For i = 1 To rs.RecordCount
  ......
  Next
End If
faster:
Dim lngRowcount
lngRowcount = rs.RecordCount
If lngRowcount = 0 Then
  ......
Else
  For i = 1 To lngRowcount
  ......
  Next
End If
在 VBScript 5.0 中,可以使用 With 语句。
slower:
rs.ActiveConnection = cnn
rs.CursorType = adOpenKeySet
rs.LockType = adLockOptimistic
faster:
With rs
  .ActiveConnection = cnn
  .CursorType = adOpenKeySet
  .LockType = adLockOptimistic
End With

10. 不要在 ASP 中声明脚本语言。
即不需要 <%@language=vbscript%>
在性能上有提高,但不明显。

11. 尽量不使用 Session。
ASP 的开发人员通常使用 ASP 内建的机制(Application 和 Session)来保存某种状态。Application 的数据可以被所有的应用共享,Session 可以保存单个用户的信息。然而,这是有代价的,尤其是 Session,你需要为每一个用户创建 Session,这是相当消耗资源的。其实有很多种方法可以替代 Session 并能完成同样的功能。( 参见文章:不使用 Session 保存数据 )。要做到不使用 Session 很容易,只需要加上 <%@EnableSessionState = False %>
另外,当你使用 frameset 时,更应该使 Session State 为 false。ASP 要求在同一会话中只能有一个请求可以执行,如果一个用户同时请求多个页面时,不会以多线程的方式处理这些请求。所以,在 frameset 中的页面是一个一个的进行处理,而不是同时进行。

12. 使用 <% Option Explicit %> 。
在ASP page 里加上<% Option Explicit %>可以提高速度。看下面的例子:
代码1
<%
FirstName = "John"
MiddleInitial = "Q"
LastName = "Public"
Address = "100 Main Street"
......
%>

代码2
<%
Dim FirstName
Dim LastName
Dim MiddleInitial
Dim Address
......
FirstName = "John"
MiddleInitial = "Q"
LastName = "Public"
Address = "100 Main Street"
......
%>

代码3
<%
Option Explicit
Dim FirstName
Dim LastName
Dim MiddleInitial
Dim Address
......
FirstName = "John"
MiddleInitial = "Q"
LastName = "Public"
Address = "100 Main Street"
......
%>

代码3比代码1速度快,代码3和代码2速度几乎一样。

13. 如果你能保证没有错误,就不要再加上 On Error Resume Next.
测试 asptoday 提供的代码,On Error Resume Next 会降低 ASP 1.42% 的速度。

14. 在页面中尽量使用一种脚本语言。

15. 把长篇大论的代码放到组件里。(如果你有这样的条件)
组件的优势在于快速,可重用,可访问系统(比如Win32)等等。虽然,它编译麻烦,需要重注册,重启 Web Server(可以用 WSC 作为过渡)。但是在处理复杂逻辑运算时,它几乎可以说是唯一的选择。而且在 IIS5.0 中创建组件的过程已优化了,不象 IIS4 那样效率低。

16. 不要动态分配数组。
Redim 一个数组,就需要为新数组分配空间。最好预先分配好空间。不过这样做好不到哪去,尽量不要使用动态数组。

17. 在长时间的循环中使用 Response.IsClientConnected 节约 CPU 时间。
For i = 1 To 1000000
  ......
  If Response.IsClientConnected Then
    ......
  Else
    Exit For
  End If
  ......
Next

18. 只在需要的时候使用 Transaction
<%@Transaction = Required %>
<%
Dim FirstName
......
根据 asptoday 文章所述,上面的代码使性能降低 140.4%。

19. 尽量少用 Server.MapPath
当你使用 Server.MapPath 时,它会产生额外的请求,使速度降低。

20. 删除 global.asa 中空的 Session_OnStart 和 Session_OnEnd

21. 利用浏览器进行确认

22. 使 Browser 和 Proxy 缓存
'使 browser 缓存
1.<% Response.Expires = 10 %>
2.<% Response.ExpiresAbsolute = #May 31,2002 13:30:15# %>
3.< META HTTP-EQUIV="Expires" VALUE="May 31,2002 13:30:15" %>
'使 proxy 缓存
<% Response.CacheControl = "Public" %>

23. 用 Server.Transfer 代替 Response.Redirect
参见文章:ASP3 的新特性

24. 在 URL 中别忘了 "/"

'bad
'browser 需要向服务器请求两次。
<a href="http://www.microsoft.com" >microsoft</a>
'good
<a href="http://www.microsoft.com/" >microsoft</a>

 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值