<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[静怡家园]]></title> 
<link>http://www.zhanghaijun.com/index.php</link> 
<description><![CDATA[书山有路勤为径，学海无涯苦作舟！]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[静怡家园]]></copyright>
<item>
<link>http://www.zhanghaijun.com/post//</link>
<title><![CDATA[提高ASP性能的22个技巧(二)]]></title> 
<author>碟舞飞扬 &lt;webmaster@zhanghaijun.com&gt;</author>
<category><![CDATA[Web开发]]></category>
<pubDate>Sun, 24 Jun 2007 18:00:20 +0000</pubDate> 
<guid>http://www.zhanghaijun.com/post//</guid> 
<description>
<![CDATA[ 
	技巧12：将常用数据复制到脚本变量中 <br/><br/>　　当访问ASP中的COM对象时，应该将常用对象数据复制到脚本变量中。着将减少COM方法调用。而COM方法调用代价相对比访问脚本数据更高。当访问Collection和 <br/>Dictonary对象时，这项技术也能消减高昂的查询代价。&nbsp;&nbsp;<br/><br/><br/>　　通常，当准备不止一次访问一个对象数据时，应该将这个数据放当一个脚本对象中。<br/><br/>　　这项优化的主要目标是Request变量（Form和QueryString变量）。例如，你的站点传递一个叫UserID的QueryString变量，假定在一个特定页UserID被引用十次。在ASP页面的顶部，将UserID的值赋给一个变量，来替代十次的调用Request <br/>(&quot;UserID&quot;)，将接生9次COM调用。 <br/><br/>　　在实际中，访问COM属性或方法的昂贵代价可能比较隐蔽。下面是一个例子，显示一段普通的代码： <br/><br/>Foo.bar.blah.baz = Foo.bar.blah.qaz(1) <br/>If Foo.bar.blah.zaq = Foo.bar.blah.abc Then &#039; ... <br/><br/>　　下面是这段代码运行的步骤： <br/><br/>1. 变量Foo被解析为一个全局对象 <br/>2. 变量bar被解析为Foo的一个成员。这触发一次COM方法调用 <br/>3. 变量blash被解析为Foo.bar的一个成员。同样，这也触发一次COM方法调用 <br/>4. 变量qaz被解析为Foo.bar.blash的一个成员。对，这也触发一次COM方法调用 <br/>5. 调用 Foo.bar.blah.qaz(1)。一个或多个COM方法调用。获取图片？ <br/>6. 重复步骤1到步骤3来解析baz。系统不知道调用qaz是否会改变对象模型，所以步骤1到步骤3又执行了一次，来解析baz <br/>7. 解析出baz是Foo.bar.blah的一个成员，执行属性put. <br/>8. 重复步骤1到步骤3来解析zaq <br/>9. 重复步骤1到步骤3来解析abc <br/><br/>　　正如你所看到的，这是多么低效（并且慢）。快速的方法是按如下代码写VBScript： <br/><br/>Set myobj = Foo.bar.blah &#039; do the resolution of blah ONCE <br/>Myobj.baz = myobj.qaz(1) <br/>If Myobj.zaq = Myobj.abc Then &#039;... <br/><br/>　　如果你用的是VBScript 5.0或更后的版本，可以使用With语句： <br/><br/>With Foo.bar.blah <br/>　　.baz = .qaz(1) <br/>　　If .zaq = .abc Then &#039;... <br/>　　... <br/>End With <br/><br/>　　技巧13：避免使用可变数组 <br/><br/>　　尽量避免使用可变数组。既然关心性能，最好还是在数组初始化的时候就设置好它可能的最大大小。当然，这不是说你明知不需要几M的内存，但还是应该给数组分配了那么多。&nbsp;&nbsp;<br/><br/><br/>　　下面的代码是一个无理使用Redim的示范： <br/><br/>&lt;% <br/>Dim MyArray() <br/>Redim MyArray(2) <br/>MyArray(0) = &quot;hello&quot; <br/>MyArray(1) = &quot;good-bye&quot; <br/>MyArray(2) = &quot;farewell&quot; <br/>... <br/>Redim Preserve MyArray(5) <br/>MyArray(3) = &quot;more stuff&quot; <br/>MyArray(4) = &quot;even more stuff&quot; <br/>MyArray(5) = &quot;yet more stuff&quot; <br/>%&gt; <br/><br/>　　简单地将数组初始化的时候定义成正确的大小（这里应该是5）远比Redim数组使它变大好。你可能会浪费一些内存（如果你最后没有用完所有的元素），但得到的是速度！<br/><br/>　　技巧14：使用响应缓冲（Response Buffering） <br/><br/>　　打开“响应缓冲”就可以缓冲整个页面的输出，这样可以减少向浏览器写的次数，提高了总体性能。每次写浏览器都要耗费一定的时间和资源，因此减少写浏览器次数能提高性能；同时，TCP/IP协议发送少的大块数据比发送多的小块数据效率更高。&nbsp;&nbsp;<br/><br/><br/>　　有两种方法可以打开响应缓冲。首先，可以使用Internet Service Manager来打开整个应用的响应缓冲。这是推荐的方法。在IIS 4.0和IIS 5.0中，新建一个应用时，响应缓冲缺省是打开的。第二种方法：针对每个独立的ASP页面，可以通过在页面顶部放置如下代码来打开响应缓冲： <br/><br/>&lt;% Response.Buffer = True %&gt; <br/><br/>　　这行语句必须在所有缓冲数据写之前执行（就是说，在所有HTML和通过Response.Cookies设置Cookie之前）。通常，最好是为整个应用打开响应缓冲；这样你就不用在每个ASP页面顶部写上面那条语句了。 <br/><br/>Response.Flush <br/><br/>　　对于响应缓冲，因为用户在看到东西之前必须等待整个页面生成，所以用户可能够感觉到ASP页面响应比较慢（虽然整体响应时间缩短了）；对一个运行时间较长的页面，可以同过Response.Buffer = False 来关掉响应缓冲；但更好的策略是使用Reponse.Flush方法。这个方法把所有已经由ASP生成的HTML输出到浏览器中。例如，一个1,000行的大表，在写完100行之后，ASP可以调用Response.Flush来强制把结果写到浏览器中，这样，用户就可以在其余行生成之前先看到100行数据。这个技术能让你两全其美—响应缓冲和渐进式地在浏览器表现数据。 <br/><br/>　　（注意，在上面的1,000行表的例子中，很多浏览器在遇到&lt;/table&gt;标记之前可能并不画出整个表。如果想让浏览器逐步显示出数据，可以将一个大表分成多个小表，然后对每个小表调用Response.Flush。新版本的IE会在下载完整个表之前显示表，并且如果指定了表的列宽，显示的速度会更快。） <br/><br/>　　另外，当产生一个非常大的页面时，响应缓冲可能会消耗掉许多的服务器内存。这个问题也可以通过使用Response.Flush来解决。<br/><br/>　　技巧15：脚本大块化和Response.Write语句<br/><br/>　　VBScript语法&lt;% = 表达式 %&gt;把“表达式”的值写到ASP输出流中；但如果响应缓冲没有打开，每个这样的语句都会想浏览器写数据，就把网络流分成很多小的包。这样会慢。同样，零星的小段脚本和HTML导致频繁的在脚本引擎和HTML之间切换，降低了性能。因此，应该使用以下技巧：把小块内嵌表达式改成调用Response.Write。例如，在下面的例子中，每行的每个字段都向响应流中写数据，并且每行都在VBScript和HTML中切换：&nbsp;&nbsp;<br/><br/><br/>&lt;table&gt; <br/>&lt;% For Each fld in rs.Fields %&gt; <br/>　　&lt;th&gt;&lt;% = fld.Name %&gt;&lt;/th&gt; <br/>&lt;% <br/>Next <br/>While Not rs.EOF <br/>%&gt; <br/>　&lt;tr&gt; <br/>　&lt;% For Each fld in rs.Fields %&gt; <br/>　　&lt;td&gt;&lt;% = fld.value %&gt;&lt;/td&gt; <br/>　&lt;% Next <br/>　&lt;/tr&gt; <br/>　&lt;% rs.MoveNext <br/>Wend %&gt; <br/>&lt;/table&gt; <br/><br/>　　下面是更有效的代码，每行只向响应流中写一次。所有的代码包含在一个VBScript块中： <br/><br/>&lt;table&gt; <br/>&lt;% <br/>　For each fld in rs.Fields <br/>　　　Response.Write (&quot;&lt;th&gt;&quot; &amp;amp; fld.Name &amp;amp; &quot;&lt;/th&gt;&quot; &amp;amp; vbCrLf) <br/>　Next <br/>　While Not rs.EOF <br/>　　Response.Write (&quot;&lt;tr&gt;&quot;) <br/>　　For Each fld in rs.Fields %&gt; <br/>　　　Response.Write(&quot;&lt;td&gt;&quot; &amp; fld.value &amp; &quot;&lt;/td&gt;&quot; &amp; vbCrLf) <br/>　　Next <br/>　　Response.Write &quot;&lt;/tr&gt;&quot; <br/>　Wend <br/>%&gt; <br/>&lt;/table&gt; <br/><br/>　　当响应缓冲被禁止时，这个技巧非成的有效。最好打开响应缓冲，然后再看看批量地Response.Write对性能的提高。<br/><br/>　　技巧16：在进入长时运算之前使用Resonse.IsClientConnected <br/><br/>　　如果用户感到不耐烦，他们可能在ASP页面计算他们的请求之前离开这个页面。如果他们点击刷新或是跳到服务器上的另一个页面，新的请求将位于ASP请求队列尾部，而中断的请求却在请求队列的中部；通常服务器在高负载情况下可能发生这种情况（服务器有很长的请求队列，同时请求次数也很多）；而这种情况又使服务器的负载情况变得更加恶劣。如果用户已经断掉连接，没有必要再执行这个ASP页面（尤其当这是一个很慢、很耗资源的页面时）；Response.IsClientConnected属性能检查出这种情况；如果属性返回False，就应该调用Resonse.End来结束剩余的页面。事实上，IIS 5.0使这种检查规律划--无论什么时候ASP准备执行一个新的请求，他先检查请求队列有多长；如果队列已经超过3秒钟，ASP就会检查客户端是否连接；如果客户端已经断开，ASP立即终止这个请求。可以使用AspQueueConnectionTestTime设置来调整3秒的超时。&nbsp;&nbsp;<br/><br/><br/>　　如果有一个非常耗时的页面要执行，也可以在页面中检查 <br/>　　Response.IsClientConnected。当响应缓冲打开时，在页面运行中使用 <br/>　　Response.Flush也能给用户操作正在执行的感觉。 <br/><br/>　　注意：在IIS 4.0上，除非你先执行了Response.Write，否则Response.IsClientConnected的结果有可能不正确；如果响应缓冲已经打开，还必须先执行Response.Flush。在IIS 5.0上，就没有这个必要了， Response.IsClientConnected工作得很正常。无论任何情况，Response.IsClientConnected总要消耗一些时间，因此，只应该在执行耗时至少超过500ms的页面中执行。首要原则是，不要在一个紧密的循环中反复调用这个属性。<br/><br/>　　技巧17：用&lt;OBJECT&gt;标记来实例化对象 <br/><br/>　　如果你想在Global.asa中引用一个不在所有的代码路径中使用的对象（特定的服务器 - 或应用 - 范围对象），使用&lt;object runat=server id=objname&gt;标记定义比用Server.CreateObject方法定义更为合适一点。因为Server.CreateObject立即创建对象，但如果过你以后不使用这个对象，则浪费了资源。&lt;object id=objname&gt;只是声明objname，但objname并没有真正创建；objname在第一次使用时才创建。<br/><br/>　　技巧18：为ADO和其他组件使用类型库声明 <br/><br/>　　当使用ADO时，开发者往往通过包含adovbs.txt来访问ADO常量。这个文件必须包含在每个使用常量的页面里；而常量文件还想相当的大，大大增加了处理每页耗费的时间和资源。&nbsp;&nbsp;<br/><br/><br/><br/>　　IIS 5.0引入了绑定组件类型库的能力；允许只引用类型库一次，然后就可以在每个ASP页面中使用。每个页面不用在为编译常量文件而消耗资源；组件开发者也不用为ASP准备VBScript包含文件了。 <br/><br/>　　可以在Global.asa中放入如下语句，来访问ADO类型库： <br/><br/>&lt;!-- METADATA NAME=&quot;Microsoft ActiveX Data Objects 2.5 Library&quot; <br/>　　　　TYPE=&quot;TypeLib&quot; UUID=&quot;&#123;00000205-0000-0010-8000- 00AA006D2EA4&#125;&quot; --&gt; <br/><br/>或 <br/>&lt;!-- METADATA TYPE=&quot;TypeLib&quot; <br/>　　　　FILE=&quot;C:&amp;amp;#92;Program Files&amp;amp;#92;Common Files&amp;amp;#92;system&amp;amp;#92;ado&amp;amp;#92;msado15.dll&quot; --&gt;<br/><br/>　　技巧19：在循环中避免进行字符串连接 <br/><br/>　　很多人喜欢用如下的循环生成字符串：&nbsp;&nbsp;<br/><br/><br/>s = &quot;&lt;table&gt;&quot; &amp; vbCrLf <br/>For Each fld in rs.Fields <br/>　　s = s &amp; &quot; &lt;th&gt;&quot; &amp; fld.Name &amp; &quot;&lt;/th&gt; &quot; <br/>Next <br/><br/>While Not rs.EOF <br/>　　s = s &amp; vbCrLf &amp; &quot; &lt;tr&gt;&quot; <br/>　　For Each fld in rs.Fields <br/>　　　　s = s &amp; &quot; &lt;td&gt;&quot; &amp; fld.value &amp; &quot;&lt;/td&gt; &quot; <br/>　　Next <br/>　　s = s &amp; &quot; &lt;/tr&gt;&quot; <br/>　　rs.MoveNext <br/>Wend <br/><br/>s = s &amp; vbCrLf &amp; &quot;&lt;/table&gt;&quot; &amp; vbCrLf <br/>Response.Write s <br/><br/>　　这种方法有一些问题。第一个就是在循环中连接字符串会使时间成二次方（quadratic）成长；或者说，运行这个循环的时间同记录的字段数目平方成正比。<br/><br/>　　下面简单的例子能更清楚地看见本质： <br/><br/>s = &quot;&quot; <br/>For i = Asc(&quot;A&quot;) to Asc(&quot;Z&quot;) <br/>　　s = s &amp; Chr(i) <br/>Next <br/><br/>　　在第一次循环中，s等于&quot;A&quot;；在第二次循环中，VBScript必须重新分配s的空间，并把字符串&quot;AB&quot;赋给s；在第三次循环中，又重新分配s的空间,重新赋值。在第N（26）次循环中，VBScript重新分配并复制了N次字符串给s，所以，总共是1+2+3+...+N=N*(N+1)/2次复制。 <br/><br/>　　在上面例子中，如果有100条记录，每个记录有5个字段，则内循环执行100*5=500次，所有复制和重新分配空间的次数相应的就是 500*500=250,000次；这还只是对一个很小的记录集。 <br/><br/>　　在这中情况下，可以通过用Response.Write或是内嵌脚本（&lt;% = fld.value %&gt;)来替换字符串连接来提高性能。如果响应缓冲已经（也应该被）打开，Response.Write只是向响应缓冲尾部添加数据，没有重新分配内存，因此非常高效。 <br/><br/>　　在一些特定的将ADO记录集转换为HTML表的情况中，可以考虑使用GetRows或GetString函数。 <br/><br/>　　如果使用JScript连接字符串，强烈推荐使用 += 操作符；就是说，用 s += &quot;some string&quot;，不要使用 s = s + &quot;some string&quot;。<br/><br/>　　技巧20：使用Server.Transfer代替Response.Redirect <br/><br/>　　Response.Redirect告诉浏览器请求另外一页。这个函数经常用来把用户跳转到登录页面或错误页面。既然redirect强制产生新的页面请求，结果就是浏览器和Web服务器间做了两次交互，Web服务器不得不多处理一次额外的请求。IIS 5.0引入了一个新的函数：Server.Transfer；这个函数直接把运行权交给同一个服务器上的另一个页面；避免了额外的浏览器到Web服务器的交互，提高了性能。<br/><br/>　　技巧21：在目录URL的尾部加上斜杠（/） <br/><br/>　　如果省略了尾部的斜杠，浏览器回发送一个请求给服务器，被告知它的请求是一个目录；然后浏览器再发送一个二次请求，不过这次URL尾部加上了斜杠，然后服务器再次响应浏览器。如果一开始就给URL加上斜杠，便可以省去无用的请求；当然，为了用户友好性，你可以在显示名字时省略尾部斜杠。&nbsp;&nbsp;<br/><br/><br/>　　例如，按如下的写法： <br/><br/>&lt;a href=http://www.webjx.com/;; title=&quot;webjx.com&quot;&gt;http://www.webjx.com&lt;;;/a&gt;<br/><br/>　　技巧22：避免使用服务器端变量 <br/><br/>　　访问服务器端变量将使站点给服务器发送一个特殊请求，收集所有的服务器端变量，不仅仅是你所访问的那一个。
]]>
</description>
</item><item>
<link>http://www.zhanghaijun.com/post//#blogcomment</link>
<title><![CDATA[[评论] 提高ASP性能的22个技巧(二)]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>http://www.zhanghaijun.com/post//#blogcomment</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>