簡介
技巧 1:在 Web 服務器上緩存常用數據
技巧 2:在 Application 或 Session 對象中緩存常用數據
技巧 3:在 Web 服務器磁盤上緩存數據和 HTML
技巧 4:避免在 Application 或 Session 對象中緩存非靈活組件
技巧 5:不要在 Application 或 Session 對象中緩存數據庫連接
技巧 6:妙用 Session 對象
技巧 7:在 COM 對象中封裝代碼
技巧 8:晚點獲取資源,早點釋放資源
技巧 9:進程外的執(zhí)行將犧牲可靠性
技巧 10:顯式使用選項
技巧 11:在子例程和函數中使用局部變量
技巧 12:將常用數據復制到腳本變量
技巧 13:避免重新定義數組
技巧 14:使用響應緩沖
技巧 15:批處理內嵌腳本和 Response.Write 語句
技巧 16:在開始長時間的任務之前先使用 Response.IsClientConnected
技巧 17:使用 OBJECT> 標記實例化對象
技巧 18:使用 ADO 對象和其他組件的 TypeLib 綁定
技巧 19:利用瀏覽器的驗證能力
技巧 20:在循環(huán)中避免字符串串聯(lián)
技巧 21:啟用瀏覽器和代理緩存
技巧 22:盡可能使用 Server.Transfer 替代 Response.Redirect
技巧 23:在目錄 URL 尾部加斜線
技巧 24:避免使用服務器變量
--------------------------------------------------------------------------------
簡介
性能是一個特性。您需要預先設計性能,或是在日后重新編寫應用程序。換句話說,什么是最大限度優(yōu)化 Active Server Pages (ASP) 應用程序性能的好策略?
本文為優(yōu)化 ASP 應用程序和"Visual Basic(R) 腳本編輯器 (VBScript)"提供了許多技巧。對許多陷阱和缺陷進行了討論。本文所列的建議均在 http://www.microsoft.com 及其他站點上進行了測試,而且工作正常。本文假定您對 ASP 開發(fā)有基本的理解,包括對 VBScript 和/或 JScript、ASP Application、ASP Session 和其他 ASP 內部對象(請求、響應和服務器)。
ASP 的性能,通常不止取決于 ASP 代碼本身。我們并不想在一篇文章中囊括所有的至理名言,只在最后列出與性能相關的資源。這些鏈接包括 ASP 和非 ASP 主題,包括"ActiveX(R) 數據對象 (ADO)"、"部件對象模型 (COM)"、數據庫和"Internet 信息服務器 (IIS)"配置。這些是我們喜歡的鏈接 - 務請關注它們。
技巧 1:在 Web 服務器上緩存常用數據
典型的 ASP 頁從后端數據庫檢索數據,然后將結果轉換為超文本標記語言 (HTML)。無論數據庫的速度如何,從內存檢索數據要比從后端數據庫檢索數據快得多。從本地硬盤讀取數據通常也要比從數據庫檢索數據快得多。因此,通??梢酝ㄟ^在 Web 服務器(在內存或磁盤)上緩存數據來改善性能。
緩存是典型的空間與時間的折衷。如果恰當地緩存數據,您將看到性能會有驚人的提高。為使緩存發(fā)揮效力,它必須保持經常重用的數據,而且重新計算這些數據的代價是昂貴的或比較昂貴的。如果緩存充滿了垃圾數據,則是對存儲器的浪費。
不經常變化的數據也是緩存的候選數據,因為您無須擔心數據與數據庫的同步問題。組合框、引用表、DHTML 碎片、可擴展標記語言 (XML) 字符串、菜單項和站點配置變量(包括數據源名稱 (DSN)、Internet 協(xié)議 (IP) 地址和 Web 路徑)都是緩存的候選數據。注意,您可以緩存數據的表示而不是數據本身。如果 ASP 頁不經常更改,而且緩存的成本也非常高(例如,整個產品目錄),請考慮預先生成 HTML,而不是在每次請求時重新繪制。
數據應緩存在何處,有哪些緩存策略?數據經常緩存在 Web 服務器內存或 Web 服務器磁盤上。下面兩個技巧討論這些選項。
技巧 2:在 Application 或 Session 對象中緩存常用數據
ASP Application 和 Session 對象為在內存中緩存數據提供了方便的容器。既可以將數據賦予 Application 對象,也可將數據賦予 Session 對象,這些數據在 HTTP 調用中將保留在內存中。Session 數據按用戶存儲,而 Application 數據在所有用戶間共享。
何時將數據載入 Application 或 Session?通常,在 Application 或 Session 啟動時加載數據。要在 Application 或 Session 啟動時加載數據,請在下面兩函數中添加相應的代碼:
Application_OnStart()
或
Session_OnStart()
。這兩個函數應該位于 Global.asa;如果沒有,可以添加這些函數。也可以在第一次需要數據時加載數據。要進行上述操作,請在 ASP 頁中添加一些代碼(或編寫可重用的腳本函數),這些代碼檢查數據是否存在,并在數據不存在時加載數據。這是稱為遲緩計算的經典性能技術的例子 - 在您的確需要它之前,不進行計算。請看例子:
%
Function GetEmploymentStatusList
Dim d
d = Application("EmploymentStatusList")
If d = "" Then
‘' FetchEmploymentStatusList 函數(不顯示)
‘' 從 DB 中取出數據,返回數組
d = FetchEmploymentStatusList()
Application("EmploymentStatusList") = d
End If
GetEmploymentStatusList = d
End Function
%>
可以為每一塊所需的數據編寫類似的函數。
數據應該以什么格式存儲?任何變量類型均可存儲,因為所有腳本變量是各不相同的。例如,可以存儲字符串、整型或數組。通常,您將以這些變量類型之一存儲 ADO 記錄集的內容。若要獲取 ADO 記錄集衍生的數據,可以手工將數據復制到 VBScript 變量中,每次一個字段。使用一個 ADO 記錄集保留函數 GetRows()、GetString() 或 Save() (ADO 2.5),會更快更簡便。完整而詳細的內容已超出了本文的范圍。下面的演示函數使用了
GetRows()
來返回記錄集數據的數組:
‘' 取記錄集,以數組返回
Function FetchEmploymentStatusList
Dim rs
Set rs = createObject("ADODB.Recordset")
rs.Open "select StatusName, StatusID from EmployeeStatus", _
"dsn=employees;uid=sa;pwd=;"
FetchEmploymentStatusList = rs.GetRows() ‘' 以數組返回數據
rs.Close
Set rs = Nothing
End Function
對上面示例的進一步改進應當是緩存該列表的 HTML,而不是緩存數組。下面是一個簡單的范例:
‘' 取記錄集,以"HTML 選項"列表返回
Function FetchEmploymentStatusList
Dim rs, fldName, s
Set rs = createObject("ADODB.Recordset")
rs.Open "select StatusName, StatusID from EmployeeStatus", _
"dsn=employees;uid=sa;pwd=;"
s = "select name=""EmploymentStatus">" vbCrLf
Set fldName = rs.Fields("StatusName") ‘' ADO 字段綁定
Do Until rs.EOF
‘' 下面一行違背了不要進行字符串連接,
‘' 但這是可以的,因為我們正在建立高速緩存
s = s " option>" fldName "/option>" vbCrLf
rs.MoveNext
Loop
s = s "/select>" vbCrLf
rs.Close
Set rs = Nothing ‘' 參見盡早釋放
FetchEmploymentStatusList = s ‘' 以字符串返回數據
End Function
在正常的情況下,可以在 Application 或 Session 作用域中緩存 ADO 記錄集本身。有兩個警告:
ADO 必須為標記的自由線程
必須使用斷開連接的記錄集。
如果不能保證滿足這兩個要求,請不要緩存 ADO 記錄集。在下面的非靈活組件和不要緩存連接技巧中,我們將討論在 Application 或 Session 作用域中存儲 COM 對象的危險。
如果在 Application 或 Session 作用域中存儲數據,這些數據將一直保留在那兒,直到在程序中改變它、Session 過期或 Web 應用程序重新啟動時為止。數據需要更新如何處理?若要用手工強制更新應用程序數據,可以調用只允許管理員訪問的數據更新 ASP 頁。另外,還可以通過函數,周期地自動刷新數據。下面的示例存儲帶緩存數據的時間戳,在指定時間間隔后刷新數據。
%
‘' 未顯示錯誤處理...
Const update_INTERVAL = 300 ‘' 刷新時間間隔,以秒計
‘' 函數返回雇傭狀態(tài)列表
Function GetEmploymentStatusList
updateEmploymentStatus
GetEmploymentStatusList = Application("EmploymentStatusList")
End Function
‘' 定期更新緩存的數據
Sub updateEmploymentStatusList
Dim d, strLastupdate
strLastupdate = Application("Lastupdate")
If (strLastupdate = "") or _
(update_INTERVAL DateDiff("s", strLastupdate, Now)) Then
‘' 注意:此處可能有兩個或多個調用。這是可以的,只不過
‘' 產生幾個不必要的取指令罷了(就此有一個工作區(qū))
‘' FetchEmploymentStatusList 函數(不顯示)
‘' 從 DB 中取數據,返回一個數組
d = FetchEmploymentStatusList()
‘' 更新 Application 對象。用 Application.Lock()
‘' 來確保一致的數據
Application.Lock
Application("EmploymentStatusList") = d
Application("Lastupdate") = CStr(Now)
Application.Unlock
End If
End Sub
其他示例,請參閱具有 Application 數據的最快列表框(英文)。
請注意,在 Session 或 Application 對象中緩存大型數組并非上策。在訪問數組元素之前,腳本語言的語法要求建立整個數組的臨時副本。例如,如果在 Application 對象中緩存了將美國郵政編碼映射到本地氣象站的字符串數組,該字符串數組有 100,000 個元素,ASP 在找出一個字符串之前,必須將所有 100,000 個氣象站復制到臨時數組中。在這種情況下,建立帶自定義方法的自定義組件,來存儲氣象站 - 或使用一個字典組件,也許更好。
請不要在倒洗澡水時把孩子一同倒掉,對這種觀點的一個新的注解是:數組提供了對內存中相鄰關鍵-數據對的快速查找和存儲。索引字典比索引數組要慢。您應該根據具體情況選擇能夠提供最佳性能的數據結構。
技巧 3:在 Web 服務器磁盤上緩存數據和 HTML
有時,數據過多不能在內存中進行緩存。"過多"是一種定性的判斷;它取決于打算消耗的內存量,還有緩存項的數量和這些項的檢索頻率??傊绻羞^多的數據要在內存中緩存,請考慮以文本或 XML 文件的形式,在 Web 服務器的硬盤上緩存數據??梢詫⒃诖疟P上緩存數據和在內存中緩存數據組合起來,為站點建立最優(yōu)的緩存策略。
注意,在度量單個 ASP 頁的性能時,在磁盤上檢索數據不一定比從數據庫中檢索數據快。但是,緩存減輕了數據庫和網絡的負荷。在高負荷情況下,這將明顯提高總體通信量。在查詢成本很高時緩存查詢的結果,緩存便非常有效,例如多表聯(lián)合或復雜的存儲過程,或緩存大型的結果集。按照慣例,測試競爭方案。
ASP 和 COM 提供了幾種構建磁盤緩存方案的工具。ADO 記錄集的 Save() 和 Open() 函數,保存和加載磁盤上的記錄集。您可以使用這些方法重寫上面 Application 數據緩存技巧中的范例代碼,用 Save() 文件替換向 Application 對象寫入數據的代碼。
還有其他一些處理文件的組件:
Scripting.FileSystemObject 使您能夠創(chuàng)建、讀取和寫入文件。
MSXML 是隨 Internet Explorer 提供的 Microsoft(R) XML 解析器,它支持保存和加載 XML 文檔。
LookupTable 對象(在 MSN 上使用的范例)是從磁盤加載簡單列表的良好選擇。
最后,請考慮在磁盤上緩存數據的表示,而不是數據本身。預制的 HTML 可以作為 .htm 或 .asp 文件存儲在磁盤上;超級鏈接可以直接指向這些文件??梢允褂蒙虡I(yè)工具,如 XBuilder 或 Microsoft(R) SQL Server 的 Internet 發(fā)行功能來自動化 HTML 生成過程。另外,可以將 HTML 片段 #include 到 .asp 文件。還可以使用 FileSystemObject 從磁盤讀取 HTML 文件或使用 XML 進行早期調整(英文)。
技巧 4:避免在 Application 或 Session 對象中緩存非靈活組件
雖然在 Application 或 Session 對象中緩存數據是個好主意,但是緩存 COM 對象可能有嚴重缺陷。將常用 COM 對象嵌入 Application 或 Session 對象通常具有吸引力。遺憾的是,很多 COM 對象,包括用 Visual Basic 6.0 或更早版本編寫的 COM 對象,在 Application 或 Session 對象中存儲時將導致嚴重的瓶頸。
特別是任何非靈活組件,在 Session 或 Application 對象中緩存時將導致性能瓶頸。靈活組件是標記為
ThreadingModel=Both
的組件(它聚集了自由線程匯集器 (FTM))或標記為
ThreadingModel=Neutral
的組件(Windows(R) 2000 和 COM+ 中新增的"中性"模型。)下列組件是非靈活的:
自由線程組件(除非它們聚集了 FTM)。
單元線程組件。
單線程組件。
已配置組件(Microsoft Transaction Server (MTS)/COM+ 庫和服務器包/應用程序)為非靈活組件,除非它們是"中性"線程的。單元線程組件和其他非靈活組件最適于在頁作用域工作(也就是說,它們在單個 ASP 頁上創(chuàng)建和銷毀)。
在 IIS 4.0 中,標記為
ThreadingModel=Both
的組件被視為靈活的。在 IIS 5.0 中,這已經不夠了。組件不僅必須標記為 Both,而且還必須聚集 FTM。靈活性文章說明了如何使得用"活動模板庫"編寫的 C++ 組件聚集 FTM。請注意,如果組件緩存接口指針,這些指針本身必須為靈活的、或者必須存儲在"COM 全局接口表 (GIT)"中。如果不能重新編譯 Both 線程組件,使它聚集 FTM,則可以將該組件標記為
ThreadingModel=Neutral
。另外,如果不希望 IIS 進行靈活性檢查(這樣,希望非靈活組件能夠存儲在 Application 或 Session 作用域中),可以在 metabase 中設置
AspTrackThreadingModel
為
True
。不主張更改
AspTrackThreadingModel
。
如果試圖在 Application 對象中存儲用
Server.createObject
創(chuàng)建的非靈活組件,IIS 5.0 將產生錯誤。可以通過在 Global.asa 中使用
object runat=server scope=application ...>
解決該問題,但是不主張這樣做,因為這將導致匯集和串行化,說明如下。
如果緩存非靈活組件,會發(fā)生什么錯誤呢?緩存在 Session 對象中的非靈活組件,將把會話"鎖定"到某個 ASP 工作器線程。ASP 維護著一個工作器線程池,它向請求提供服務。通常,新的請求由第一個可用的工作器線程來處理。如果 Session 被鎖定到某個線程,則該請求將不得不等待它所關聯(lián)的線程變?yōu)榭捎?。打個比方:您進入一個超市,挑選了一些食品,然后在第 3 號收款臺交款。從這以后,每當您在這個超市購買食品,都不得不始終在第 3 號收款臺交款,即使是在其他收款臺人少或沒人時。
將非靈活組件存儲在 Applicaton 作用域甚至會對性能產生更嚴重的影響。ASP 將不得不創(chuàng)建專用的線程來運行非靈活的、Applicaton 作用域內的組件。這將導致兩種后果:所有調用不得不被匯集到該線程,而且所有調用被串行化。匯集意味著:參數不得不存儲在內存的共享區(qū);對該專用線程執(zhí)行昂貴的上下文切換;組件的方法被執(zhí)行;結果匯集到共享區(qū)域;以及經過另一個昂貴的上下文切換,使控制權返回原來的線程。串行化意味著所有方法必須一個挨一個地運行(同一時刻只能運行一個方法)。兩個不同的 ASP 工作器線程不可能同時執(zhí)行共享組件上的方法。這將扼殺并行機制,尤其是在多處理器計算機上。更壞的是,所有非靈活的、Application 作用域內的組件都將共享一個線程("Host STA"),所以串行化的影響更加嚴重。
是否感到困惑?下面我們提出幾個通用規(guī)則。如果您正在用 Visual Basic (6.0) 或更早版本編寫對象,請不要將它們緩存在 Application 或 Session 對象中。如果您不知道對象的線程模型,就不要緩存它。不要緩存非靈活對象,而應當在每頁上創(chuàng)建并釋放它們。對象將直接運行在 ASP 工作器線程上,這樣,將不會發(fā)生匯集或串行化。如果 COM 對象正運行在 IIS 框中,而且如果它們沒有花很長時間來初始化和取消,性能將是足夠的。注意,不要用該方法使用單線程對象。小心:VB 可以創(chuàng)建單線程的對象!如果您必須以該方式使用單線程的對象(如 Microsoft Excel 電子表格),則不要期望有很高的吞吐量。
當 ADO 被標記為自由線程時,則緩存 ADO 記錄集是安全的。要將 ADO 標記為自由線程,請使用 Makfre15.bat 文件,該文件通常位于如下目錄中:\\Program Files\Common\System\ADO。
警告: 如果您正在用 Microsoft Access 作為數據庫,則不應當將 ADO 標記為自由線程。通常,ADO 記錄集還必須是斷開連接的,如果您不能控制站點的 ADO 配置(例如,您是獨立的軟件廠商 [ISV],將 Web 應用程序賣給客戶,然后由他們來管理他們自己的配置),那么不緩存記錄集可能會更好。
詞典組件也是靈活對象。LookupTable 從數據文件加載它的數據,并且它對組合框數據和配置信息是有用的。來自 Duwamish Books 的 PageCache 對象提供了目錄語義,和 Caprock Dictionary 的表現(xiàn)一樣。這些對象或它們的派生對象可以構成有效緩存策略的基礎。注意,Scripting.Dictionary 對象不是靈活的,所以不應當存儲在 Application 或 Session 作用域。
技巧 5:不要在 Application 或 Session 對象中緩存數據庫連接
緩存 ADO 連接通常是不好的策略。如果一個 Connection 對象存儲在 Application 中,并在所有頁上使用,那么所有頁將競爭使用該連接。如果 Connection 對象存儲在 ASP Session 對象中,那么將為每個用戶創(chuàng)建數據庫連接。這將連接池的好處毀于一旦,并對 Web 服務器和數據庫產生不必要的壓力。
取代緩存數據庫連接的方法是,在每個使用 ADO 的 ASP 頁上創(chuàng)建并取消 ADO 對象。這是個有效的方法,因為 IIS 具有內置的數據庫連接池。更準確的說,IIS 自動啟用 OLEDB 和 ODBC 連接池。這確保了創(chuàng)建并取消每個頁上的連接將是有效的。
由于被連接的記錄集中存儲有對數據庫連接的引用,所以,不應當在 Application 或 Session 對象中緩存被連接的記錄集。但是,可以安全地緩存斷開連接的記錄集,因為它不包含對其數據連接的引用。要斷開記錄集的連接,請執(zhí)行如下兩個步驟:
Set rs = Server.createObject("ADODB.RecordSet")
rs.CursorLocation = adUseClient ‘' 第 1 步
‘' 植入帶數據的記錄集
rs.Open strQuery, strProv
‘' 現(xiàn)在斷開記錄集同數據提供者和數據源的連接
rs.ActiveConnection = Nothing ‘' 第 2 步
有關連接池的詳細信息,請參閱 ADO 和 SQL Server(英文)引用。
技巧 6:妙用 Session 對象
在肯定了在 Applications 和 Sessions 中緩存的優(yōu)點之后,我們建議您避免使用 Session 對象。下面將會談到,當用于忙碌站點時,Sessions 有幾個缺點。所謂忙碌,通常是指站點每秒請求數百頁或同時有數千個用戶。該技巧對于必須進行水平擴展的站點,即那些利用多個服務器來適應負載或執(zhí)行容錯功能的站點來說,更加重要。對于較小的站點,如 intranet 站點,Sessions 的便利,與開銷相比也是值得的。
為了翻新,ASP 自動為每個訪問 Web 服務器的用戶創(chuàng)建一個 Session。每個 Session 有大約 10 KB 內存開銷(在存儲在 Session 中的任何數據中是最高的),并使所有的請求都慢了一點。Session 一直保持活動狀態(tài),直到達到可配置的超時(通常 20 分鐘)為止。
Session 最大的問題不是性能而是可伸縮性。Session 不能跨越 Web 服務器;一旦在一個服務器上創(chuàng)建了 Session,它的數據就保持在那里。這意味著,如果您在 Web 領域中使用 Sessions,您將不得不為每個用戶的請求設計一種策略,以便始終將這些請求引向用戶的 Session 所在的服務器。這被稱為將用戶"粘"到 Web 服務器上。術語"粘性會話"即來源于此。由于 Session 沒有保持到磁盤上,所以,當 Web 服務器崩潰時,被"粘住"的用戶將丟失他們的 Sessions 狀態(tài)。
用于實施粘性會話的策略包括硬件和軟件解決方案。如 Windows 2000 Advanced Server 中的網絡負載平衡解決方案和 Cisco 公司的"本地指向器"解決方案可以實施粘性會話,但以犧牲一些可伸縮性為代價。這些解決方案并不完美。我們不主張您現(xiàn)在全盤推翻您的軟件解決方案(我們過去常用 ISAPI 篩選器和 URL 矯直對方案進行檢查)。
Application 對象也不能跨越服務器;如果您需要在 Web 領域內共享并更新 Application 數據,則需要使用后端數據庫。但只讀的 Application 數據在 Web 領域中仍然有用。
如果只是為了增加正常運行時間(用于處理故障轉移和服務器維護),大多數執(zhí)行重要任務的站點將需要部署至少兩臺 Web 服務器。所以,在設計執(zhí)行重要任務的應用程序時,您將需要實施"粘性會話",或者簡單地避開 Sessions 以及其他任何在單個 Web 服務器上存儲用戶狀態(tài)的狀態(tài)管理技術。
如果當前沒有使用 Sessions,請確保將它們關閉??梢酝ㄟ^"Internet 服務管理器"(請參閱 ISM 文檔)來為應用程序執(zhí)行該操作。如果決定使用 Sessions,可以采取幾個方法來將對性能的影響降低到最小。
可以將不需要 Sessions 的內容(如"幫助"屏幕、訪問者區(qū)域等)移動到關閉了 Sessions 的、單獨的 ASP 應用程序中??梢灾痦撎崾?ASP:在給定的頁中您不需要 Session 對象;使用位于 ASP 頁頂端的如下指令:
% @EnableSessionState=False %>
使用該指令的一個很好的原因是,Session 給框架集帶來了有趣的問題。ASP 保證任何時候只執(zhí)行一個來自 Session 的請求。這樣可以確保如果瀏覽器為一個用戶請求了多個頁時,在每一時刻只有一個 ASP 請求將進入 Session;這就避免了在訪問 Session 對象時出現(xiàn)多線程問題。遺憾的是,結果,框架集中的所有頁均被以串行化方式繪制,一個接一個地,而不是同時地。這樣,用戶可能不得不等待很長時間才能得到所有框架內容。這意味著:如果某些框架頁不信任 Session,一定要使用
@EnableSessionState=False
指令告訴 ASP。
作為使用 Session 對象的替代方式,有很多方法可以用來管理 Session 狀態(tài)。對于狀態(tài)數量較小的情況(不到 4 KB),通常建議使用 Cookies、QueryString 變量和隱藏形式的變量。對于較大數量的數據,如購物推車,則使用后端數據庫是最合適的選擇。關于在 Web 服務器領域中的狀態(tài)管理技術已經有很多資料。詳細信息,請參閱 會話狀態(tài)(英文)。
技巧 7:在 COM 對象中封裝代碼
如果您有很多 VBScript 或 JScript,那么您可以通過把代碼移動到已編譯的 COM 對象來經常改進它們的性能。已編譯的代碼通常比被解釋代碼運行得更快。已編譯的 COM 對象可以通過"早期綁定"訪問其他 COM 對象,這種調用 COM 對象方法的手段,比腳本所使用的"后期綁定"更有效。
將代碼封裝在 COM 對象種有如下好處(超越性能):
COM 對象是將表達邏輯與業(yè)務邏輯分隔開來的好辦法。
COM 對象啟用了代碼重用。
很多開發(fā)商發(fā)現(xiàn),用 VB、C++ 或 Visual J++ 書寫的代碼,比 ASP 更容易調試。
COM 對象有一些缺點,包括初始開發(fā)時間以及需要不同的編程技巧。需要警告您的是,封裝"少"量的 ASP 可能會導致性能降低,而不是提高。通常,在少量 ASP 代碼封裝到 COM 對象時出現(xiàn)這樣的情況。這時候,創(chuàng)建和調用 COM 對象的開銷,超過了已編譯代碼的好處。至于 ASP 腳本和 COM 對象代碼怎樣合并才能產生最佳性能還有待測試。注意,與 Windows NT(R) 4.0/IIS 4.0 相比,Microsoft 已經在 Windows 2000/IIS 5.0 中極大地提高了腳本和 ADO 性能。這樣,已編譯代碼對 ASP 代碼的性能優(yōu)勢已經隨著 IIS 5.0 的引入而降低。
有關在 ASP 中使用 COM 對象的優(yōu)缺點的更多討論,請參閱 ASP 組件準則和用 COM 和 Microsoft Visual Basic 6.0 對分布式應用程序進行編程(英文)。如果您的確部署了 COM 組件,要對它們進行強度測試是非常重要的。實際上,所有 ASP 應用程序都應當作為正式過程進行強度測試。
技巧 8:晚點獲取資源,早點釋放資源
這是個小技巧。通常,最好晚點獲取資源而要早點釋放資源。這些資源包括 COM 對象、文件句柄和其他資源。
ADO 連接和記錄集是這種優(yōu)化的首要目標。當您使用完記錄集,就是說用它的數據打印完一個表格后,請立即將它釋放,而不是等到頁的末尾。將您的 VBScript 變量設置為
Nothing
是最好的做法。不要讓記錄集簡單地脫離作用域。同時,應當釋放任何有關的 Command 或 Connection 對象。(不要忘了對記錄集或"連接"調用
Close()
,在將它們設置為
= Nothing
之前。)這將縮短數據庫必須為您調整資源的時間跨度,并將數據庫連接盡可能快地釋放給連接池。
技巧 9:進程外的執(zhí)行將犧牲可靠性
ASP 和 MTS/COM+ 都有允許您以可靠性換取性能的配置選項。當建立和部署應用程序時,應當理解這種交換。
ASP 選項
ASP 應用程序可以配置為以三種方式之一運行。在 IIS 5.0 中引入了術語"隔離級"來描述這些選項。三個隔離級值分別是低、中和高:
低級隔離。該隔離級在所有版本的 IIS 中受到支持,并且是最快的。它在主 IIS 進程 Inetinfo.exe 中執(zhí)行 ASP。如果 ASP 應用程序崩潰,則 IIS 也將崩潰。(要在 IIS 4.0 下重新啟動 IIS,Web 站點管理員需要使用工具,如 InetMon,來監(jiān)視站點,如果服務器失敗,將運行批處理文件來重新啟動服務器。而 IIS 5.0 則引入了可靠的重新啟動,它將自動重新啟動失敗的服務器。)
中級隔離。IIS 5.0 引入了這個新隔離級,它稱為進程外的,這是因為 ASP 運行在 IIS 進程之外。在中級隔離中,所有被配置按"中級"運行的 ASP 應用程序,將共享單個進程空間。這將減少在一個服務器上運行多個進程外的 ASP 應用程序所需的進程數。中級是 IIS 5.0 中默認的隔離級。
高級隔離。在 IIS 4.0 和 IIS 5.0 中受到支持,高級隔離也是進程外的。如果 ASP 崩潰,則 Web 服務器并不崩潰。ASP 應用程序將在下一個 ASP 請求時自動重新啟動。使用高級隔離,每個被配置為按高級運行的 ASP 應用程序,將在其自己的進程空間中運行。這樣可以保護 ASP 應用程序彼此不受干擾。它的缺點是它需要為每個 ASP 應用程序建立獨立的進程。當需要在一個服務器上主持十多個應用程序時,會增加很多開銷。
那么,哪個選項是最好的呢?在 IIS 4.0 中,運行進程外的應用程序會極大地影響性能。在 IIS 5.0 中,做了許多工作,使得進程外運行 ASP 應用程序對性能產生的影響降到了最低。實際上,在大多數測試中,在 IIS 5.0 中的 ASP 進程外應用程序,要比 IIS 4.0 中的進程內應用程序運行得更快。無論如何,進程內(低隔離級)在兩種平臺上仍然產生了最好的性能。但是,如果您的命中率相對較低或最大吞吐量較低,選擇低隔離級不會有太大的好處。所以,除非您需要每個 Web 服務器每秒處理數百或數千個頁面,否則沒有必要選擇低隔離級。同樣,應當測試多種配置并判斷哪種情形最適合您。
注意: 當您進程外運行 ASP 應用程序(中級或高級隔離)時,則在 NT4 上它們將運行在 MTS 中,而在 Windows 2000 上它們將運行在 COM+ 中。即,在 NT4 上它們運行在 Mtx.exe 中,而在 Windows 2000 上它們運行在 DllHost.exe 中。在"任務管理器"中,您可以看見這些正在運行的進程。還可以看見 IIS 如何為進程外的 ASP 應用程序配置 MTS 程序包或 COM+ 應用程序。
COM 選項
COM 組件也有三個配置選項,雖然與 ASP 選項不完全相似。COM 組件可以被:"不配置"、配置為"庫應用程序"或配置為"服務器應用程序"。"不配置"是指不向 COM+ 注冊組件。組件將運行在調用者的進程空間,就是說,它們是"進程中"的。"庫應用程序"也是進程中的,但受惠于 COM+ 的服務,包括安全性、事務和環(huán)境支持。"服務器應用程序"被配置為在其自己的進程空間中運行。
您可能看到,不配置的組件比庫應用程序優(yōu)點稍微多些。您還可能看到"庫應用程序"比"服務器應用程序"有很大的性能優(yōu)點。這是因為"庫應用程序"與 ASP 運行在同一個進程中,而"服務器應用程序"則運行在自己的進程中。內部進程調用的開銷要比進程內調用的開銷大得多。而且,當在進程之間傳遞數據(如記錄集)時,必須在兩個進程之間復制所有的數據。
缺點!當使用"COM 服務器應用程序"時,如果要在 ASP 和 COM 之間傳遞對象,請確保對象實現(xiàn)"按值匯集",即 MBV。實現(xiàn) MBV 的對象將其自身從一個進程復制到另一個進程。這比另一種方式好,在另一種方式中,對象留在創(chuàng)建它的進程中,而其他進程則重復調用創(chuàng)建使用該對象的進程。被斷開連接的 ADO 記錄集將是按值匯集的,已連接的記錄集則不是。Scripting.Dictionary 并不實現(xiàn) MBV,不會在進程之間傳遞。最后,要另外告訴 VB 程序員的是:MBV 不是通過傳遞參數
ByVal
獲得的。MBV 是由原始組件創(chuàng)作者實現(xiàn)的。
怎么辦?
如果您想要以性能與可靠性的合理交換來完成您的配置,我們的推薦如下:
在 IIS 4.0 上,使用 ASP 的低隔離級別,并使用"MTS 服務器包"。
在 IIS 5.0 上,使用 ASP 的中隔離級別,并使用"COM+ 庫應用程序"。
這些是很一般的準則;通常讓公司以中或高隔離級別運行 ASP,而單一目的的 Web 服務器可運行于低隔離級別。請權衡折中并自行決定滿足需求的配置。
技巧 10:顯式使用選項
在 .asp 文件中顯式使用
選項 Explicit
。置于 .asp 文件開頭的這一指令,強制開發(fā)人員聲明所有要使用的變量。許多開發(fā)人員認為這有助于調試應用程序,因為它避免了錯誤鍵入變量名稱而不經意地新建變量(例如,
MyXLMString=...
而非
MyXMLString=)
。
也許更重要的是,聲明的變量比未聲明的變量快。實際上,腳本運行時,在每次使用未聲明變量時按照名稱引用。而聲明的變量,在編譯或運行時分配了序號。這樣,聲明的變量按照該序號引用。由于
選項 Explicit
強制變量聲明,因此保證聲明了所有變量而實現(xiàn)快速訪問。
技巧 11:在子例程和函數中使用局部變量
局部變量是在子例程和函數中聲明的變量。在子例程和函數中,局部變量訪問要快于全局變量訪問。使用局部變量還可以使代碼更加清晰,因此盡可能使用局部變量。
技巧 12:將常用數據復制到腳本變量
在 ASP 中訪問 COM 時,應該將常用的對象數據復制到腳本變量中。這將削減 COM 方法的調用,COM 方法的調用與訪問腳本變量相比,要相對昂貴些。在訪問 Collection 和 Dictionary 對象時,這一技術也可以削減了昂貴的查找。
通常,如果打算多次訪問對象數據,請將數據放入腳本變量。該優(yōu)化的主要目標是 Request 變量(Form 和 QueryString 變量)。例如,您的站點可能傳遞一個名為 UserID 的 QueryString。假定該 UserID 變量要在特定頁中引用 12 次。請不要調用
Request("UserID")
12 次,而在 ASP 頁的開頭將 UserID 賦予某個變量。然后就在頁中使用該變量。這將節(jié)省 11 次 COM 方法調用。
在實際中,訪問 COM 屬性或方法暗藏著繁復的過程和大量的開銷。下面是一個示例,它只是些相當普通的代碼(從語法上講):
Foo.bar.blah.baz = Foo.bar.blah.qaz(1)
If Foo.bar.blah.zaq = Foo.bar.blah.abc Then ‘' ...
在運行這段代碼時,將發(fā)生下列事件:
變量
Foo
被解析為全局變量。
變量
bar
被解析為
Foo.
的成員。這將產生 COM 方法調用。
變量
blah
被解析為
Foo.bar
的成員。這也將產生 COM 方法調用。
變量
qaz
被解析為
foo.bar.blah
的成員。是的,這也將產生 COM 方法調用。
調用
Foo.bar.blah.quaz(1)
。又一次產生 COM 方法調用。理解這幅圖了嗎?
執(zhí)行步驟 1 到 3 將再次解析
baz
。系統(tǒng)不知道調用
qaz
是否更改對象模型,因此步驟 1 到 3 必須再次執(zhí)行解析
baz
。
將
baz
解析為
Foo.bar.blah
的成員。進行屬性置入。
再次執(zhí)行步驟 1 到 3 并解析
zaq
。
再次執(zhí)行步驟 1 到 3 并解析
abc
。
正如所見,這是非??膳碌牡托剩ǘ曳浅BS?VBScript 編寫該代碼實現(xiàn)的快速方法為:
Set myobj = Foo.bar.blah ‘' 對 blah 做一次解析
Myobj.baz = myobj.qaz(1)
If Myobj.zaq = Myobj.abc Then ‘'...
如果您使用的是 VBScript 5.0 或更高版本,則可用
With
語句來寫這段代碼:
With Foo.bar.blah
.baz = .qaz(1)
If .zaq = .abc Then ‘'...
...
End With
請注意該技巧對 VB 編程同樣有效。
技巧 13:避免重新定義數組
盡量避免
Redim
數組。從關心性能的角度來說,如果計算機受物理內存的限制,最好一開始將數組的維數設置為最差方案 - 而不要將維數設置為最佳方案,再根據需要重新定義維數。這并不意味著明知道不需要那么多而就是應該分配太多的內存。
下面代碼展示了您沒有必要地使用了
Dim
和
Redim
來解決。
%
Dim MyArray()
Redim MyArray(2)
MyArray(0) = "hello"
MyArray(1) = "good-bye"
MyArray(2) = "farewell"
...
‘' 一些別的代碼中,這里您不需要更多的空間,然后 ...
Redim Preserve MyArray(5)
MyArray(3) = "more stuff"
MyArray(4) = "even more stuff"
MyArray(5) = "yet more stuff"
%>
更好的辦法是只須一開始
Dim
數組為正確的大?。ū纠袨?5),而不是
Redim
數組,再加大數組。這可能會浪費一點兒內存(如果沒有用盡所有元素),但是獲得的是速度。
技巧 14:使用響應緩沖
您可以通過打開"響應緩沖區(qū)"來緩沖值得輸出的整個頁。這將寫入瀏覽器的數據量降為最小,從而提高總體性能。每次寫入都會有大量開銷(包括 IIS 和通過電纜發(fā)送的數據量),因此寫入的越少越好。TCP/IP 的工作效率,在發(fā)送少量大的數據塊時明顯高于發(fā)送大量小的數據塊時,原因在于它的低速啟動和 Nagling 算法(用于最小化網絡阻塞)。
打開響應緩沖有兩種方法。第一種,可以使用"Internet 服務管理器"為整個應用程序打開響應緩沖。這是推薦的方法,在 IIS 4.0 和 IIS 5.0 中,在默認情況下,為新的 ASP 應用程序打開響應緩沖。第二種,逐頁將下列代碼行放在 ASP 頁的開頭,從而啟用響應緩沖:
% Response.Buffer = True %>
該行代碼必須在任何響應數據寫入瀏覽器之前執(zhí)行(也就是說,在任何 HTML 出現(xiàn)在 ASP 腳本中之前和任何 Cookies 被使用
Response.Cookies
集合設置之前)。通常,最好是為整個應用程序打開響應緩沖。這允許省略上面每頁中的代碼行。
Response.Flush
響應緩沖的通病是用戶感覺 ASP 頁響應遲鈍(盡管總體響應時間改善了),因為他們需要等到整個頁生成后才能看見該頁。對于長時間運行的頁面,可以通過設置
Response.Buffer = False
關閉響應緩沖。但是,更好的策略是使用
Response.Flush
方法。該方法刷新由 ASP 繪入瀏覽器的所有 HTML。例如,繪制了具有 1,000 行的表的 100 行后,ASP 可以調用
Response.Flush
強制將結果繪制到瀏覽器;這允許用戶在其余的行準備好之前先看到頭 100 行。該技術給了您兩個舉世無雙的好東西 - 響應緩沖與瀏覽器中數據的逐步顯示的組合。
(注意,在上面 1,000 行表的示例中,許多瀏覽器,在看到 /table> 結束標記之前不會開始繪制表。請檢查目標瀏覽器的支持性。要解決該問題,請將表分割為具有較少行的多個表,然后在每個表后面調用
Response.Flush
。新版本的 Internet Explorer 將在表完全下載之前繪制表,特別是如果指定表的列寬則繪制速度更快;這避免強制 Internet Explorer 通過度量每個單元格的內容來計算列寬。)
響應緩沖的另一個通病是在生成大型頁時將使用服務器的大量內存。對于該問題,除了要求生成大型頁的技巧外,還可以通過巧妙地使用
Response.Flush
來解決。
技巧 15:批處理內嵌腳本和 Response.Write 語句
VBScript 語法
% = expression %>
將"
表達式
"的值寫入 ASP 輸出流。如果響應緩沖沒有打開,則這些語句的每一句都會導致通過網絡,以許多小型包的形式,向瀏覽器寫入數據。這是非常慢的。另外,解釋少量腳本和 HTML,將導致在腳本引擎和 HTML 之間切換,也降低了性能。因此,請使用下面技巧:用對
Response.Write
的一個調用,替換內嵌的密集組合表達式。例如,在下面范例中,每行每字段有一個對響應流的寫入,每行都有許多 VBScript 和 HTML 之間的切換:
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>
下面是更有效的代碼,每行中有一個對響應流的寫入。所有代碼均包含在一個 VBScript 塊內:
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.Write
是否對性能有幫助。
(在這一特例中,構建表的主體的嵌套循環(huán) (
While Not rs.EOF...
) 可以被精心構造的、對 GetString 的調用所替代。)
技巧 16:在開始長時間的任務之前先使用 Response.IsClientConnected
如果用戶失去耐心,他們可以在開始執(zhí)行他們的請求之前放棄 ASP 頁。如果他們單擊了 Refresh 或跳轉到服務器的其他頁上,在 ASP 請求隊列的末尾將有一個新的請求,而在隊列的中間有一個斷開連接的請求。這通常發(fā)生在服務器處于高負荷的情況下(它有一個很長的請求隊列,相應的響應時間也很長),這只能使情況更糟。如果用戶不再連接,將沒有執(zhí)行 ASP 頁的點(特別是低速、重量級的 ASP 頁)??梢允褂?
Response.IsClientConnected
屬性檢查這種情況。如果它返回
False
,則應調用
Response.End
并放棄該頁的剩余內容。實際上,每當 ASP 要執(zhí)行新的請求時,IIS 5.0 便將該方法編碼,來檢查隊列中的請求有多長。如果在那里超過了 3 秒鐘,ASP 會檢查客戶是否仍然連接著,如果客戶已斷開連接,就立即結束該請求。您可以使用 metabase 中的
AspQueueConnectionTestTime
設置,調整這 3 秒的超時時間。
如果有某頁執(zhí)行了很長時間,您可能還想按一定的時間間隔檢查
Response.IsClientConnected
。在啟用響應緩沖之后,按一定的時間間隔執(zhí)行
Response.Flush
,告訴用戶正在進行的是哪些事情,是個好辦法。
注意 在 IIS 4.0 中,
Response.IsClientConnected
將不能正常工作,除非首先執(zhí)行
Response.Write
。如果啟用了緩沖,也需要執(zhí)行
Response.Flush
。在 IIS 5.0 中則不必如此 -
Response.IsClientConnected
工作得很好。在任何情況下,
Response.IsClientConnected
都要有些開銷,所以,只有在執(zhí)行至少要用 500 毫秒(如果想維持每秒幾十頁的吞吐量,這是一個很長的時間了)的操作前才使用它。作為通常的規(guī)則,不要在緊密循環(huán)的每次迭代中調用它,例如當繪制表中的行,可能每 20 行或每 50 行調用一次。
技巧 17:使用 OBJECT> 標記實例化對象
如果需要引用不能在所有代碼路徑中使用的對象(尤其是服務器 - 或應用程序 - 作用域的對象),則使用 Global.asa 中的
object runat=server id=objname>
標記來聲明它們,而不是使用
Server.createObject
方法。
Server.createObject
立刻創(chuàng)建對象。如果以后不使用那個對象,就不要浪費資源。
object id=objname>
標記聲明了 objname,但實際上 objname 此時并沒有創(chuàng)建,直到它的方法或屬性第一次被使用時才創(chuàng)建。
這是遲緩計算的另一個例子。
技巧 18:使用 ADO 對象和其他組件的 TypeLib 聲明
當使用 ADO 時,開發(fā)人員經常包含
adovbs.txt
來獲得對 ADO 不同常量的訪問權。該文件必須包含在要使用這些常量的每一頁中。該常量文件非常大,給每個 ASP 頁增加了很多編譯時間和腳本大小方面的開銷。
IIS 5.0 提供了綁定到組件類型庫的能力。允許您在每個 ASP 頁上引用一次類型庫并使用它。每頁不需要為編譯常量文件付出代價,并且組件開發(fā)人員不必為在 ASP 中的使用而生成 VBScript #include 文件。
要訪問 ADO 類型庫,請將下列語句之一放入 Global.asa 中。
!-- METADATA NAME="Microsoft ActiveX Data Objects 2.5 Library"
TYPE="TypeLib" UUID="{00000205-0000-0010-8000-00AA006D2EA4}" -->
或者
!-- METADATA TYPE="TypeLib"
FILE="C:\Program Files\Common Files\system\ado\msado15.dll" -->
技巧 19:利用瀏覽器的驗證能力
流行的瀏覽器具有對以下功能的高級支持,例如 XML、DHTML、Java 小程序以及遠程數據服務。請盡量利用這些功能。所有這些技術,都可以通過執(zhí)行客戶端的驗證和數據緩存,減少了與 Web 服務器之間的往返。如果您正在運行智能瀏覽器,該瀏覽器可以為您進行一些驗證(例如,在運行 POST 之前檢查信用卡的校驗和否有效)。重申一次,請盡量使用這些功能。由于削減了客戶端到服務器的往返路程,將減少對 Web 服務器的壓力,并且削減了網絡通信量(雖然發(fā)送給瀏覽器的初始頁面可能更大),服務器訪問的所有后端資源也削減了。而且用戶不必經常提取新頁,使用戶的感受好一些。這并不減輕對服務器端驗證的需要。還是應該經常進行服務器端的驗證。這樣能夠防止由于某些原因從客戶端來的壞數據,例如黑客,或者不運行客戶端驗證程序的瀏覽器。
許多站點由獨立于瀏覽器創(chuàng)建的 HTML 組成。這一點經常阻礙開發(fā)人員利用可以提高性能的流行瀏覽器功能。對于真正高性能的、必須關心瀏覽器的站點,良好的策略是針對流行的瀏覽器優(yōu)化您的頁面。在 ASP 中使用"瀏覽器性能組件",很容易檢測到瀏覽器的功能。諸如 Microsoft FrontPage 等工具,能幫助您設計使用所希望的目標瀏覽器和 HTML 版本的代碼。更詳細的討論,請查看 When is Better Worse? Weighing the Technology Trade-Offs(英文)。
技巧 20:在循環(huán)中避免字符串串聯(lián)
許多人在循環(huán)中創(chuàng)建類似這樣的字符串:
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
這種方法有幾個問題。首先,重復連接字符串所花費的時間,以二次方曲線的速率增長;粗略地計算,運行循環(huán)所花費的時間,與記錄數乘以字段數的平方成正比。舉一個簡單的例子,便能清楚地說明這一點。
s = ""
For i = Asc("A") to Asc("Z")
s = s Chr(i)
Next
在第一次迭代中,得到一個字符的字符串
"A"
。在第二次迭代中,VBScript 必須重新分配字符串并復制兩個字符
"AB"
到
。在第三次迭代中,它必須再次重新分配
,并復制三個字符到
。在第 N 次(26 次)迭代中,它必須重新分配并復制 N 個字符到
。就是 1+2+3+...+N 的和,為 N*(N+1)/2 次復制。
在以上記錄集的例子中,如果有 100 條記錄和 5個字段,則內部的循環(huán)將執(zhí)行 100*5 = 500 次,并且完成所有復制和重新分配所花費時間,將與 500*500 = 250,000 成正比。對一個大小適度的記錄集,將有很多次復制。
在該例子中,代碼可以改進:字符串的連接將被
Response.Write()
或內嵌腳本 (
% = fld.Value %>
) 所替代。如果打開響應緩沖,這個操作將會很快,因為
Response.Write
僅僅將數據添加到響應緩沖的末尾。不再重新分配,因而非常有效。
特別是在將 ADO 記錄集轉換到 HTML 表時,請考慮使用 GetRows 或 GetString。
如果用 JScript 連接字符串,強烈建議使用
+=
操作符;即用
s += "某字符串",
而不是
s = s + "某字符串"
。
技巧 21:啟用瀏覽器和代理緩存
默認情況下,ASP 禁用瀏覽器和代理中的緩存。這將很有意義,因為 ASP 生來就是動態(tài)的,具有潛在地對時間敏感的信息。如果有一個不需要對每次查看進行刷新的頁,則應該啟用瀏覽器和代理緩存。這使得瀏覽器和代理能在某一段時間內,使用某一頁的緩存副本,這時間的長短可以控制。緩存能明顯減輕服務器負荷,使用戶的感受好一些。
哪種動態(tài)頁可以緩存?舉例說明:
天氣頁,每 5 分鐘更新一次。
列出新聞的主頁或新聞發(fā)布的主頁,每天更新 2 次。
公共基金運營列表,基本的統(tǒng)計數小時更新 1 次。
請注意,使用瀏覽器或代理緩存,只有很少的命中被記錄到 Web 服務器上。如果想精確測量所有頁面查看或者張貼廣告,也許不喜歡使用瀏覽器和代理緩存。
瀏覽器緩存是由 Web 服務器發(fā)往瀏覽器的 HTTP 截至期限標題控制的。ASP 提供了兩種發(fā)送標題的機制。要將頁面設置為在未來某個分鐘數后過期,請設置
Response.Expires
屬性。以下的例子通知瀏覽器:內容在 10 分鐘后過期:
% Response.Expires = 10 %>
設置
Response.Expires
為負數或 0 則禁用緩存。一定要使用較大的負數,例如 -1000 (大于一天),來克服服務器時鐘和瀏覽器時鐘之間的差異。第二個屬性
Response.ExpiresAbsolute
,允許設置內容過期的指定時間:
% Response.ExpiresAbsolute = #May 31,2001 13:30:15# %>
如果不想使用 Response 對象設置過期時間,可以將 META> 標記寫入 HTML,通常寫在 HTML 文件的 HEAD> 內部。一些瀏覽器會響應這條指令,但代理不會。
META HTTP-EQUIV="Expires" VALUE="May 31,2001 13:30:15">
最后,可以標識內容對 HTTP 代理緩存是否有效,請使用
Response.CacheControl
屬性。設置屬性為"Public",允許代理緩存內容。
% Response.CacheControl = "Public" %>
默認情況下,該屬性設置為"Private"。注意,不應當為顯示某用戶專用數據的頁啟用代理緩存,因為代理也許為屬于其他用戶的用戶頁面服務。
技巧 22:盡可能使用 Server.Transfer 替代 Response.Redirect
Response.Redirect
通知瀏覽器,請求一個不同的頁面。該函數經常用于重定向用戶到登錄或錯誤頁面。既然重定向強制一個新頁請求,瀏覽器就必須做兩次到 Web 服務器的往返,而且 Web 服務器必須處理額外的請求。IIS 5.0 引入一個新的函數,
Server.Transfer
,該函數執(zhí)行傳送到相同服務器上的不同 ASP 頁。這樣避免了額外的、從瀏覽器到 Web 服務器的往返,從而改善了整體系統(tǒng)性能,同時改善了對用戶的響應時間。請查看重定向中的新方向(英文),它討論了
Server.Transfer
和
Server.Execute
。
也可以查看Leveraging ASP in IIS 5.0中有關 IIS 5.0 和 ASP 3.0 新功能的完全列表。(英文)
技巧 23:在目錄 URL 尾部加斜線
相關的技巧是,一定要定在指向目錄的 URL 尾部加斜線
(/)
。如果省略了斜線,瀏覽器將向服務器提出請求,僅通知它正尋找一個目錄。然后瀏覽器發(fā)出第二個請求,在 URL 末尾添加斜線,然后服務器將那個目錄的默認文檔作為響應,或者如果沒有默認文檔并且目錄瀏覽已被啟用,就以目錄列表作為響應。添加了斜線便省去了第一個沒用的往返。出于對用戶的友好,也許想要在顯示的名稱的末尾省略斜線。
例如,寫:
a title="MSDN Web
Workshop">http://msdn.microsoft.com/workshop/a>
它還適用于指向在 Web 站點主頁的 URL:請使用下面的: a >,不要用 a >.
技巧 24:避免使用服務器變量
訪問服務器變量將引起 Web 站點向服務器提出特殊的請求,然后收集所有的服務器變量,并不止是需要的那個。這好像從發(fā)霉的閣樓中的文件夾中檢索某條特殊的信息一樣。當想要某條信息時,在訪問該信息之前必須先上閣樓取得文件夾。這與請求服務器變量時,性能訪問出現(xiàn)第一次請求服務器變量所發(fā)生的一樣。后續(xù)的對其他服務器變量的訪問不會引起性能訪問。
從不訪問不合格的 Request 對象(例如, Request("Data") )。對于不在 Request.Cookies 、 Request.Form 、 Request.QueryString 或 Request.ClientCertificate 中的項,有對 Request.ServerVariables 的隱含調用。
Request.ServerVariables
集合比其他集合慢很多。