zoukankan      html  css  js  c++  java
  • web优化之js动态合并 动态压缩 去掉js重复引用 js缓存 js延迟加载

    做web前段也有一段时间了,对于web中js文件的加载有些体会想跟大家一起分享一下。

    1.首先说说js文件的合并和压缩吧

    为了便于集中式管理js的合并和压缩我们创建一个Js.ashx文件来专门处理合并压缩,这里我们借用Yahoo.Yui.Compressor工具来压缩我们的js文件

    代码如下:

     public class Js : IHttpHandler
        {
    
            public void ProcessRequest(HttpContext context)
            {
                context.Response.ContentType = "text/javascript";
                HttpRequest request = context.Request;
                HttpResponse response = context.Response;
                if (!request.QueryString.AllKeys.Contains("href"))
                {
                    response.Write("No Content");
                }
                else
                {
                    string href = context.Request.QueryString["href"].Trim();
                    string[] files = href.Split(new string[]{",",""},StringSplitOptions.RemoveEmptyEntries);
                    foreach (string fileName in files)
                    {
                        string filePath = context.Server.MapPath(fileName);
                        if (File.Exists(filePath))
                        {
                            string content = File.ReadAllText(filePath, Encoding.UTF8);
                            content = JavaScriptCompressor.Compress(content);
                            response.Write(content);
                        }
                        else
                        {
                            response.Write("\r\n未找到源文件"+filePath+"\r\n");
                        }
                    }
                }
            }
    
            public bool IsReusable
            {
                get
                {
                    return false;
                }
            }
        }

    当我们在浏览器访问js时如:

    http://localhost:58798/js.ashx?href=scripts/jquery.lazyload.js,scripts/jquery.validate.js

    返回结果如图:


    但是在实际开发中很多项目为了追求js的合并和压缩,开发很不友好把js的引用放在一个地方,写了很长的一串啊,如上面js引用。

    下面说说如何改善吧:

     public static class Extensions
        {
            const string jsFileKey = "JSFileKey";
            static string jshandlerUrl = string.Empty;
            public static string JsHandlerUrl
            {
                get
                {
                    if (string.IsNullOrEmpty(jshandlerUrl))
                    {
                        jshandlerUrl = ConfigurationManager.AppSettings["jsHandlerUrl"] ?? string.Empty;
                    }
                    return jshandlerUrl;
                }
            }
    
            public static void AppendJsFile(this HtmlHelper htmlHelper, string jsFile, int group = 1)
            {
                NameValueCollection jsFiles = null;
                if (htmlHelper.ViewContext.HttpContext.Items.Contains(jsFileKey))
                {
                    jsFiles = htmlHelper.ViewContext.HttpContext.Items[jsFileKey] as NameValueCollection;
                }
                else
                {
                    jsFiles = new NameValueCollection();
                    htmlHelper.ViewContext.HttpContext.Items.Add(jsFileKey, jsFiles);
                }
                if (jsFiles.AllKeys.Contains(group.ToString()))
                {
                    string fileUrl = jsFiles[group.ToString()];
                    if (!fileUrl.Contains(jsFile))
                        jsFiles.Add(group.ToString(), jsFile);
                }
                else
                {
                    jsFiles.Add(group.ToString(), jsFile);
                }
    
                htmlHelper.ViewContext.HttpContext.Items[jsFileKey] = jsFiles;
            }
    
            public static MvcHtmlString RenderJsFile(this HtmlHelper htmlHelper)
            {
                NameValueCollection jsFiles = null;
                StringBuilder content = new StringBuilder();
                if (htmlHelper.ViewContext.HttpContext.Items.Contains(jsFileKey))
                {
                    jsFiles = htmlHelper.ViewContext.HttpContext.Items[jsFileKey] as NameValueCollection;
                    List<string> jsKeys = jsFiles.AllKeys.OrderBy(x => x).ToList<string>();
    
                    string jsFormat = "<script type=\"text/javascript\" src=\"{0}\"></script>";
                    foreach (string key in jsKeys)
                    {
                        string jsFile = jsFiles[key];
                        content.AppendFormat(jsFormat, JsHandlerUrl + jsFile);
                        //htmlHelper.ViewContext.HttpContext.Response.Write(string.Format(jsFormat, JsHandlerUrl + jsFile));
                    }
                }
                return new MvcHtmlString(content.ToString());
            }
        }

    这样在开发的时候我们书写代码就很方便了如:

    @{Html.AppendJsFile("Scripts/jquery.lazyload.js");}  

    这样把所有的js文件缓存起来,最后在调用  @Html.RenderJsFile() 一次性全部输出js。如:


    至于为什么这样写我就不多说了,这种思想在mvc中的RenderPartial和RenderAction都是可用的,如

    重复的js引用也在Js.ashx去掉是不是很方便啊

    最后生成的html代码:


    2.下面我们来看看js的延迟加载,为了实现js延迟加载我们需要引用相关的js,在这里我用的是lazyload.js,具体请参考http://blog.csdn.net/dz45693/article/details/7529584

    延迟加载后的效果


    在文档加载前只加载了一个2.2k的lazyload.js文件,其他的js文件都在ready后加载。

    相应的html代码


    3.下面再来看看js的缓存吧,缓存涉及到要做服务端和客户端缓存,客户端缓存说白了就是做304返回

    修改后的代码:

      class CacheItem
            {
                public string Content { set; get; }
                public DateTime Expires { set; get; }
            }
            public void ProcessRequest(HttpContext context)
            {
                context.Response.ContentType = "text/javascript";
                HttpRequest request = context.Request;
                HttpResponse response = context.Response;
                if (!request.QueryString.AllKeys.Contains("href"))
                {
                    response.Write("No Content");
                }
                else
                {
                    string href = context.Request.QueryString["href"].Trim();
                    string[] files = href.Split(new string[] { ",", "" }, StringSplitOptions.RemoveEmptyEntries);
                    CacheItem item = null;
                    object obj = HttpRuntime.Cache.Get(href);//服务端缓存
                    if (null == obj)
                    {
                        StringBuilder allText = new StringBuilder();
                        foreach (string fileName in files)
                        {
                            string filePath = context.Server.MapPath(fileName);
                            if (File.Exists(filePath))
                            {
                                string content = File.ReadAllText(filePath, Encoding.UTF8);
                                content = JavaScriptCompressor.Compress(content);
                                //response.Write(content);
                                allText.Append(content);
                            }
                            else
                            {
                                // response.Write("\r\n未找到源文件"+filePath+"\r\n");
                                allText.Append("\r\n未找到源文件" + filePath + "\r\n");
                            }
                        }//end foreach
                         item = new CacheItem() { Content = allText.ToString(), Expires = DateTime.Now.AddHours(1) };
                         HttpRuntime.Cache.Insert(href, item, null, item.Expires, TimeSpan.Zero);
                    }
                    else
                    {
                        item = obj as CacheItem;
                    }
                    if (request.Headers["If-Modified-Since"] != null && TimeSpan.FromTicks(item.Expires.Ticks - DateTime.Parse(request.Headers["If-Modified-Since"]).Ticks).Seconds < 100)
                    {
                        response.StatusCode = 304;
                       // response.Headers.Add("Content-Encoding", "gzip");
                        response.StatusDescription = "Not Modified";  
                    }
                    else
                    {
                        response.Write(item.Content);
                        SetClientCaching(response, DateTime.Now);
                    }
                }//end else href
            }
            private void SetClientCaching(HttpResponse response, DateTime lastModified)
            {
                response.Cache.SetETag(lastModified.Ticks.ToString());
                response.Cache.SetLastModified(lastModified);
                //public 以指定响应能由客户端和共享(代理)缓存进行缓存。  
                response.Cache.SetCacheability(HttpCacheability.Public);
                //是允许文档在被视为陈旧之前存在的最长绝对时间。  
                response.Cache.SetMaxAge(new TimeSpan(7, 0, 0, 0));
                //将缓存过期从绝对时间设置为可调时间  
                response.Cache.SetSlidingExpiration(true);
            }  

    运行效果如图:


    代码下载地址:http://download.csdn.net/detail/dz45693/4272920

  • 相关阅读:
    linux 网络相关
    工作随笔
    python
    trouble-shooting
    MySQL常见问题总结
    根据 Request 获取客户端 IP
    文件上传按钮优化
    Linux中RabbitMQ安装
    linux 完全卸载MySQL
    Linux 下安装 MySQL-5.7.24
  • 原文地址:https://www.cnblogs.com/majiang/p/2580793.html
Copyright © 2011-2022 走看看