Web性能優化-合並js與css,減少請求


   Web性能優化已經是老生常談的話題了, 不過筆者也一直沒放在心上,主要的原因還是項目的用戶量以及頁面中的js,css文件就那幾個,感覺沒什么優化的。人總要進步的嘛,最近在被angularjs吸引着,也用了angularjs開發了一個項目,那感覺真的是誰用誰知道。

   angularjs的好處我就不在這里廢話了,有興趣的請自行度娘。背景是這樣的, 在這個使用angularjs開發的項目中,由於自己的粗心導致頁面打開很慢,傻了吧唧的引用了未壓縮的js文件,將近1M的js啊,我還傻乎乎的建索引,優化sql,然而最終並沒有什么卵用,最后還是在查請求的時候發現angularjs未壓縮的文件原來那么大,然后就用了min版本的,瞬間問題解決了。話說到此優化應該就結束了吧,但作為一個有理想,有抱負的程序員咱不能太容易滿足,所以決定再進行優化下,數據庫和程序都已經優化了,那后面就只能來減少網絡的請求數來進行優化了。再加上在學習angularjs的過程中,發現js也可以像咱們的C#一樣進行模塊化開發(請原諒俺對於前端的小白),那進行模塊化的時候就需要將不同的模塊放在不同的文件中,這樣問題就來了,我們頁面的請求數會增多,減少頁面請求的方式就是將多個css文件或者js文件進行合並,最簡單的方法就是人工的進行合並再一起。但人工多傻啊,咱們可是勵志改變世界的程序員們,咱不能人工,咱必須智能,所以在園子里逛了下,多少找到了點頭緒,參考了下別人的博客,總結下下面的方法。

  首先先講下思路,添加一個asp.net處理程序,然后在頁面中的script標簽中的src的值設置為這個asp.net的處理程序的路徑,並加上一個參數(css類似),如下所示:

  <link href="/Css/CombineFiles.axd?fn=index" rel="stylesheet" />

  在程序中我們可以獲取到fn的值,然后根據fn的值在/css/路徑下面找到對應的文件名,如fn的值為index,那么就在/css/文件夾下面找到文件名問index.txt的文件,然后打開讀取文件中的內容,如下所示:

 

 

第一行表示的是當前請求的css文件,如果是js文件,則第一行為js。后面的每行則表示的為文件名。在上圖中的例子中,表示的是,當前請求的是a.css,b.css,c.css合並和的文件。那我們只需要將三個文件合並后並輸入就行了。下面直接上代碼:

 public class CombineFiles : IHttpHandler
    {
        #region IHttpHandler Members
        /// <summary>
        /// 緩存key值
        /// </summary>
        private const string CacheKeyFormat = "_CacheKey_{0}_";
        public bool IsReusable
        {
            get { return true; }
        }

        public void ProcessRequest(HttpContext context)
        {
            HttpRequest request = context.Request;
            HttpResponse response = context.Response;

            string cachekey = string.Empty;
            bool flag = false;//標志是否是最新合並的內容
            string fn = request.QueryString["fn"];
            if (!string.IsNullOrEmpty(fn))
            {
                cachekey = string.Format(CacheKeyFormat, fn);
                CompressCacheItem cacheItem = HttpRuntime.Cache[cachekey] as CompressCacheItem;
                if (cacheItem == null)
                {
                    flag = true;
                    string path = context.Server.MapPath("");
                    StringBuilder sb = new StringBuilder();
                    //找到請求的文本文件
                    var con = File.ReadAllText(string.Format("{0}\\{1}.txt", path, fn)).
                        Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    response.ContentType = con[0] == "css" ? "text/css" : "text/javascript";
                    for (int i = 1; i < con.Length; i++)
                    {
                        var filename = string.Format("{0}\\{1}.{2}", path, con[i],con[0]);
                        if (File.Exists(filename))
                        {
                            string readstr = File.ReadAllText(filename, Encoding.UTF8);
                            sb.Append(readstr);
                        }
                    }
                    cacheItem = new CompressCacheItem() { Type = con[0], Content = sb.ToString(), Expires = DateTime.Now.AddDays(30) };
                    HttpRuntime.Cache.Insert(cachekey, cacheItem, null, cacheItem.Expires, TimeSpan.Zero);
                }

                string ifModifiedSince = request.Headers["If-Modified-Since"];
                if (!string.IsNullOrEmpty(ifModifiedSince)&&cacheItem.Expires>DateTime.Parse(ifModifiedSince)&&!flag)
                {
                    response.StatusCode = (int)System.Net.HttpStatusCode.NotModified;
                    response.StatusDescription = "Not Modified";
                }
                else
                {
                    response.Write(cacheItem.Content);
                    SetClientCaching(response, cacheItem.Expires);
                }
            }

        }

        private void SetClientCaching(HttpResponse response, DateTime expires)
        {
            response.Cache.SetETag(DateTime.Now.Ticks.ToString());
            response.Cache.SetLastModified(DateTime.Now);

            //public 以指定響應能由客戶端和共享(代理)緩存進行緩存。    
            response.Cache.SetCacheability(HttpCacheability.Public);

            //是允許文檔在被視為陳舊之前存在的最長絕對時間。 
            response.Cache.SetMaxAge(TimeSpan.FromTicks(expires.Ticks));

            response.Cache.SetSlidingExpiration(true);
        }
        private class CompressCacheItem
        {
            /// <summary>
            /// 類型 js 或 css 
            /// </summary>
            public string Type { get; set; } // js css  
            /// <summary>
            /// 內容
            /// </summary>
            public string Content { set; get; }
            /// <summary>
            /// 過期時間
            /// </summary>
            public DateTime Expires { set; get; }
        }

        #endregion
    }

 

此代碼是在園子里一個園友的博客的基礎上進行改進的。鏈接找不到了,在這里就不貼出來了。

 

最后呢,需要在配置文件中加入如下配置信息:

<configuration>
    <system.web>
      <compilation debug="true" targetFramework="4.0" />
    <httpHandlers>
      <add verb="GET" path="*.axd" type="Angular.CombineFiles"/>
    </httpHandlers>
    </system.web>

</configuration>

 

上面的代碼中可以實現功能是,合並js或css,並將其緩存起來,當每次請求時都會判斷當前瀏覽器中是否有緩存,且是否有效,如果有效則直接響應302,告訴瀏覽器本地緩存是可以使用的,不需要從服務器端重新下載,介紹了很多流量,並且提高了速度。假如,在項目升級的過程中,修改了js或者css,想讓瀏覽器強制下載最新的文件時,可將HttpRuntime.Cache中的緩存移除,這樣當重新請求時,會重新合並文件,並響應到客戶端。

如下所示:

 HttpRuntime.Cache.Remove(string.Format("_CacheKey_{0}_","index"));

 

over

 

另外,在這里推廣下咱們的微信開發交流群,這里是一群致力於C#微信開發交流的平台,歡迎各位同行進行交流。也可以到群論壇與大家一起交流學習。

微信開發交流的論壇(微兔碼農說

 如有疑問加群一起交流,我需要廣大屌絲小伙伴的反饋與建議,   點擊這里給我發消息

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM