加速ASP.NET页面--组合,最小化和压缩Javascript文件

这几年,网站做的越来越吸引人,而大部分吸引人的因素来自于脚本Javascript. 程序员们使用不同的js库和框架来使得网页更吸引人和人性化。

我们的问题是什么?

      1.你使用了太多的JS。而JS从不同的地方引用,有时候文件的总大小一度达到500K,甚至更多,这是影像网速一个致命的问题,特别是对于一些网络连接速度慢的人来说。解决这个问题的最好的方法是使用gzip来压缩JS文件(一会我们会详细讲解).

      2.JS文件在浏览器中的加载方法是one by one,也就是说,加载各种不同的JS文件需要请求多次,而且请求的时间是有你的网速有关的。如果在你的网页中有非常多的JS文件,在网页加载的同时就会造成一个非常大的延迟。大家可以使用Firebug(一个非常流行而且必须的Firefox组件)来测试一下。

      这不是CSS或者IMAGE的情况。如果你想引用多个CSS文件或者IMAGE的话,它们也会被一起加载。

      最好的解决方案是组合多个JS文件到一个文件中,这样就会去掉在读取多个JS文件时的延迟。

加速ASP.NET页面--组合,最小化和压缩Javascript文件

OK,说了半天,我们应该怎么做?

答案非常简单!组合多个文件并且压缩它们,将请求降至最低。接下来我们要通过一些步骤来实现这些功能。但是我们要怎么做呢?

最简单的方式使用HTTP Hanlder组合JS文件并且来压缩请求。这样就能代替多个JS文件的引用所导致的多个请求。首先,我们先像这样引用这个handler

< script  type ="text/javascript"  src ="ScriptCombiner.axd?s=Site_Scripts&v=1" ></ script >

 ScriptCombiner.axd是我们的HTTP Handler。有两个参数要传递给这个Handler,s和v. 

S代表设置的名称,V代表版本。你可以利用参数改变你的版本号,这样可以保证浏览器每次都加在一个新的JS文件,而不是从cache中取出。S设置名称表示被Handler处理的JS的文件列表。我们将这个列表保存在一个txt文档中,文件在App_Data文件夹中。文件包括我们需要引用的JS文件的相对路径。格式如下:

~/Scripts/ScriptFile1.js   
~/Scripts/ScriptFile2.js  

    大部分的工作在HTTP Handler中完成。下面我来解释一下在Handler中发生了什么:

1.从TXT文件中取得JS文件列表,并且加在这个JS文件列表。

2.去读每个JS文件中的内容,并且把这些内容组合成一个字符串。

3.使用Minifier来剔除字符串中的注释和空格回车。

4.使用Gzip来压缩字符串。

5.将压缩的结果放入Cache中,这样,我们就不必再次处理每次请求。

接下来,我们需要做一些步骤来使得这个handler更容易理解。我创建了一个例子(如果需要源码,请发送请求至我的邮箱:[email protected])。

下面是项目截图:

加速ASP.NET页面--组合,最小化和压缩Javascript文件

HTTP Handler 包括一些helper方法。我来简单介绍一下这些方法

CanGzip方法检测浏览器是否支持gzip.

代码
private   bool  CanGZip(HttpRequest request)   
{   
    
string  acceptEncoding  =  request.Headers[ " Accept-Encoding " ];   
    
if  ( ! string .IsNullOrEmpty(acceptEncoding)  &&    
         (acceptEncoding.Contains(
" gzip " ||  acceptEncoding.Contains( " deflate " )))   
       
return   true ;   
    
return   false ;   
}  

大部分工作都有ProcessRequest来完成 

代码
 1  public   void  ProcessRequest(HttpContext context)   
 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的轻量级的组件。 

using  (Stream writer  =  isCompressed  ?   (Stream)( new  GZipStream(memoryStream, CompressionMode.Compress)) : memoryStream)

最后我们来做的更好一些

我们可以将整个处理过程作的更方便使用。 

代码
 1  public   static   string  GetScriptTags( string  setName,  int  version)   
 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用来描述之前返回的文件名的数组 

代码
 1  private   static   string [] GetScriptFileNames( string  setName)   
 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  }  

 我们需要在页面中引用如下:

<% =  ScriptCombiner.GetScriptTags( " Site_Scripts " 1 %>

最后,我们需要设置web.config.将Http Handler加入。 

代码
 1  < configuration >   
 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 >   

 

总结: 你可以在网上搜到很多类似的方法,我仅仅是把那些方法组合了一下。如果需要源码,请发邮件至我的邮箱:[email protected].

你可能感兴趣的:(JavaScript)