这几年,网站做的越来越吸引人,而大部分吸引人的因素来自于脚本Javascript. 程序员们使用不同的js库和框架来使得网页更吸引人和人性化。
我们的问题是什么?
1.你使用了太多的JS。而JS从不同的地方引用,有时候文件的总大小一度达到500K,甚至更多,这是影像网速一个致命的问题,特别是对于一些网络连接速度慢的人来说。解决这个问题的最好的方法是使用gzip来压缩JS文件(一会我们会详细讲解).
2.JS文件在浏览器中的加载方法是one by one,也就是说,加载各种不同的JS文件需要请求多次,而且请求的时间是有你的网速有关的。如果在你的网页中有非常多的JS文件,在网页加载的同时就会造成一个非常大的延迟。大家可以使用Firebug(一个非常流行而且必须的Firefox组件)来测试一下。
这不是CSS或者IMAGE的情况。如果你想引用多个CSS文件或者IMAGE的话,它们也会被一起加载。
最好的解决方案是组合多个JS文件到一个文件中,这样就会去掉在读取多个JS文件时的延迟。
OK,说了半天,我们应该怎么做?
答案非常简单!组合多个文件并且压缩它们,将请求降至最低。接下来我们要通过一些步骤来实现这些功能。但是我们要怎么做呢?
最简单的方式使用HTTP Hanlder组合JS文件并且来压缩请求。这样就能代替多个JS文件的引用所导致的多个请求。首先,我们先像这样引用这个handler
ScriptCombiner.axd是我们的HTTP Handler。有两个参数要传递给这个Handler,s和v.
S代表设置的名称,V代表版本。你可以利用参数改变你的版本号,这样可以保证浏览器每次都加在一个新的JS文件,而不是从cache中取出。S设置名称表示被Handler处理的JS的文件列表。我们将这个列表保存在一个txt文档中,文件在App_Data文件夹中。文件包括我们需要引用的JS文件的相对路径。格式如下:
~/Scripts/ScriptFile2.js
大部分的工作在HTTP Handler中完成。下面我来解释一下在Handler中发生了什么:
1.从TXT文件中取得JS文件列表,并且加在这个JS文件列表。
2.去读每个JS文件中的内容,并且把这些内容组合成一个字符串。
3.使用Minifier来剔除字符串中的注释和空格回车。
4.使用Gzip来压缩字符串。
5.将压缩的结果放入Cache中,这样,我们就不必再次处理每次请求。
接下来,我们需要做一些步骤来使得这个handler更容易理解。我创建了一个例子(如果需要源码,请发送请求至我的邮箱:xiaocaige@vip.sina.com)。
下面是项目截图:
HTTP Handler 包括一些helper方法。我来简单介绍一下这些方法
CanGzip方法检测浏览器是否支持gzip.
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
{
string acceptEncoding = request.Headers[ " Accept-Encoding " ];
if ( ! string .IsNullOrEmpty(acceptEncoding) &&
(acceptEncoding.Contains( " gzip " ) || acceptEncoding.Contains( " deflate " )))
return true ;
return false ;
}
大部分工作都有ProcessRequest来完成
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
2 {
3 this .context = context;
4 HttpRequest request = context.Request;
5
6
7 string setName = request[ " s " ] ?? string .Empty;
8 string version = request[ " v " ] ?? string .Empty;
9
10
11 bool isCompressed = this .CanGZip(context.Request);
12
13
14 if ( ! this .WriteFromCache(setName, version, isCompressed))
15 {
16 using (MemoryStream memoryStream = new MemoryStream( 8092 ))
17 {
18 using (Stream writer = isCompressed ? (Stream)( new ICSharpCode.SharpZipLib.GZip.GZipOutputStream(memoryStream)) : memoryStream)
19 {
20 StringBuilder allScripts = new StringBuilder();
21 foreach ( string fileName in GetScriptFileNames(setName))
22 allScripts.Append(File.ReadAllText(context.Server.MapPath(fileName)));
23
24 var minifier = new JavaScriptMinifier();
25 string minified = minifier.Minify(allScripts.ToString());
26
27 byte [] bts = Encoding.UTF8.GetBytes(minified);
28 writer.Write(bts, 0 , bts.Length);
29 }
30 byte [] responseBytes = memoryStream.ToArray();
31 context.Cache.Insert(GetCacheKey(setName, version, isCompressed),
32 responseBytes, null , System.Web.Caching.Cache.NoAbsoluteExpiration,
33 CACHE_DURATION);
34
35 this .WriteBytes(responseBytes, isCompressed);
36 }
37 }
38 }
我们使用sharpZipLib来执行压缩。这是一个.NET的轻量级的组件。
最后我们来做的更好一些
我们可以将整个处理过程作的更方便使用。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
2 {
3 string result = null ;
4 #if (DEBUG)
5 foreach ( string fileName in GetScriptFileNames(setName))
6 {
7 result += String.Format( " \n<script type=\ " text / javascript\ " src=\ " { 0 } ? v = { 1 }\ " ></script> " , VirtualPathUtility.ToAbsolute(fileName), version);
8 }
9 #else
10 result += String.Format( " <script type=\ " text / javascript\ " src=\ " ScriptCombiner.axd ? s = { 0 } & v = { 1 }\ " ></script> " , setName, version);
11 #endif
12 return result;
13 }
GetScriptFileName用来描述之前返回的文件名的数组
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
2 {
3 var scripts = new System.Collections.Generic.List < string > ();
4 string setPath = HttpContext.Current.Server.MapPath(String.Format( " ~/App_Data/{0}.txt " , setName));
5 using (var setDefinition = File.OpenText(setPath))
6 {
7 string fileName = null ;
8 while (setDefinition.Peek() >= 0 )
9 {
10 fileName = setDefinition.ReadLine();
11 if ( ! String.IsNullOrEmpty(fileName))
12 scripts.Add(fileName);
13 }
14 }
15 return scripts.ToArray();
16 }
我们需要在页面中引用如下:
最后,我们需要设置web.config.将Http Handler加入。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
2 < system.web >
3 < httpHandlers >
4 < add verb ="POST,GET" path ="ScriptCombiner.axd" type ="ScriptCombiner, App_Code" />
5 </ httpHandlers >
6 </ system.web >
7 <!-- IIS 7.0 only -->
8 < system.webServer >
9 < handlers >
10 < add name ="ScriptCombiner" verb ="POST,GET" path ="ScriptCombiner.axd" preCondition ="integratedMode" type ="ScriptCombiner, App_Code" />
11 </ handlers >
12 </ system.webServer >
13 </ configuration >
总结: 你可以在网上搜到很多类似的方法,我仅仅是把那些方法组合了一下。如果需要源码,请发邮件至我的邮箱:xiaocaige@vip.sina.com.