挣脱浏览器的束缚(2) - 别让脚本引入坏了事
2007-01-20 01:25 Jeffrey Zhao 阅读(6820) 评论(43) 编辑 收藏 举报现在哪里还找得到不引入JavaScript脚本文件的Web应用?使用脚本文件的好处多多,其中最重要的可能就是提供缓存能力了。使用脚本文件之后再加上缓存,可以大大降低数据传输量,提高页面打开的速度。不过脚本文件的引入也不是简单得不值一提,我们完全有能力来优化它。
小心传统的脚本引入方式带来的性能问题
现在的Web应用所需的脚本越来越多,一张页面下载几百K的脚本也不再是难以想象的事情了,这就直接导致页面需要更长的时间来加载脚本。不过传统的脚本引入方式(使用<script />)会造成什么问题?再查看这点之前,我们先写一个HttpHandler来模拟一个需要较长时间才能加载的脚本。这很简单,我们只要创建一个Http Handler来做到这一点,如下:
public class Scripts : IHttpHandler { public void ProcessRequest (HttpContext context) { context.Response.ContentType = "application/x-javascript"; System.Threading.Thread.Sleep(1500); context.Response.Write("//"); } public bool IsReusable { get { return false; } } }
我使用Thread.Sleep函数使线程休眠1.5秒,然后输出一个注释符。这样就保证了页面加载该文件需要比较长的时间,也可以将脚本的执行时间降到最低。
然后我们就写个最简单的页面,来测试一下加载这些文件的结果:
<html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server" id="aaa"> <title>Untitled Page</title> <script type="text/javascript" language="javascript" src="Scripts.ashx?a"></script> <script type="text/javascript" language="javascript" src="Scripts.ashx?b"></script> <script type="text/javascript" language="javascript" src="Scripts.ashx?c"></script> <script type="text/javascript" language="javascript" src="Scripts.ashx?d"></script> <script type="text/javascript" language="javascript" src="Scripts.ashx?e"></script> </head> <body> ... </body> </html>
在IE里打开页面,看看这些脚本加载的情况。请注意,您可以使用IE Dev Toolbar来禁用Cache(图5)。
图5:IE中传统方式加载脚本的情况
真可谓是相当的整齐。不过整齐的背后是较低的性能:脚本文件一个一个被加载,所有脚本文件被加载完需要用8秒多时间。
那么FireFox的表现又如何?我们使用同样的页面来测试一下(图6)。
图6:FireFox中传统方式加载脚本的情况
嘿,情况差不多。
其实出现这个状况是By Design的。从上面这个简单的例子里可能还无法看出,事实上,当浏览器遇到<script />标签时,它会开始加载脚本文件,而此时页面的其它加载行为则会全部停止,包括HTML的呈现,页面或图片的下载等等。这是因为浏览器“怀疑”这些脚本文件中的一些行为可能会再页面中输出HTML。自然,我们可以使用document.write方法这么做。而很多可以放在网站中的第三方小部件,都是靠脚本文件里的document.write方法来生成HTML的。
这就让用户不太好受了。为什么我的浏览器只能建立一个连接?为什么不能一起下载?我们的带宽不是浪费了很多吗?这些都没错。还记得前一段时间台湾地震使一些Blog无法打开或者打开很慢吗?这很可能就是在页面中使用<script />引入脚本文件时造成的问题:文件下载特别慢,甚至会超时。而且当时我的blog也遇到这个问题。解决方案很简单,把<script />去掉便是。或者,您可以将<script />元素放置在“页尾”代码中,这样,页面就会打开地比较快了——不过当然,那个文件很可能还在继续加载脚本中。
这就是提高了所谓的“感知性能(Perceived Performance)”,简单的说,就是用户“感受”到的性能。用户会发现页面已经打开了,虽然还没有完全加载完,例如Snap Preview还无法工作。
尝试打破传统脚本引入的瓶颈
现在的脚本越做越大了,一个200K的文件,如果以20K每秒的速度下载也要10秒。如果这十秒结束之后又来个十秒……这样的网页加载速度太可怕了。我们必须尝试着打破这个瓶颈。
很有趣的是,如果您在页面中使用document.write来写一个<script />元素的话,这些脚本就可以并行下载了。我们就用下面的代码进行尝试吧:
<html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server" id="aaa"> <title>Untitled Page</title> <script type="text/javascript" language="javascript"> document.write( '<script type="text/javascript" language="javascript"' + ' src="Scripts.ashx?a"><' + '/script>'); document.write( '<script type="text/javascript" language="javascript"' + ' src="Scripts.ashx?b"><' + '/script>'); document.write( '<script type="text/javascript" language="javascript"' + ' src="Scripts.ashx?c"><' + '/script>'); document.write( '<script type="text/javascript" language="javascript"' + ' src="Scripts.ashx?d"><' + '/script>'); document.write( '<script type="text/javascript" language="javascript"' + ' src="Scripts.ashx?e"><' + '/script>'); </script> </head> <body> ... </body> </html>
这样的做法似乎有些复杂,不过应该还算直观。上面代码的目的就是在页面中“写入”<script />元素,以达到引入脚本文件的目的。还是用事实说话,先来看一下IE中打开页面的效果吧(图6):
图7:IE中使用document.write加载脚本的情况
状况好多了。可以看出总是有两个脚本文件在同时下载,虽然还是受制于浏览器对于每个Domain只有2个连接的限制,但是页面加载时间已经从8秒多锐减到不到5秒了。这实在是一个绝好的消息。那么再公布一个好消息,使用这种方式引入脚本文件的话,脚本文件的执行顺序与脚本文件出现的顺序相同。我们只要安排好脚本文件的顺序,这样就可以保证脚本执行的正确性了。
嘿嘿,不管怎么说这个方法还是非常容易使用的,不是吗?那么让我们欢呼雀跃吧,因为优化就是这么简单!
很可惜事情的发展并不如我们想象的那么单纯。我们还没有试过FireFox下的状况呢。看了FireFox加载页面的数据统计图,可能就会知道,我们离目标还有很大的距离——因为它的状况和图6的显示状况完全相同,document.write这种做法在FireFox里没有起到任何作用。
为什么IE的表现和FireFox的表现不同呢?可能这就要问一下浏览器的开发者了,我们现在要做的,可能只是根据结果来为我们的应用想出更好的解决方案。
路漫漫其修远兮。