MVC页面加载速度优化小记

 前言:

      最近做一个地图展示页面,业务初期没什么问题,运行一阵后报错:

Error during serialization or deserialization using the JSON JavaScriptSerializer. 
The length of the string exceeds the value set on the maxJsonLength property.

Google 了一下,原来是由于业务数据的增多, ajax 后台返回时报错,参考网上的方法,在返回时设置一下 MaxJsonLength

            var jsonResult = Json(jsonString);
            jsonResult.MaxJsonLength = int.MaxValue;
            return jsonResult;

报错的问题是解决了,可还有一个问题就是页面加载时间过长。为了地图展示的效果,不能进行数据分页。

期间尝试了很多方法,记录如下:

 列表与地图同步:

       页面的布局是左边显示数据列表,右边显示 GoogleMap 。刚开始拼列表的 html 和地图的初始化、加载是在同一个方法里面执行的,这样的效果就是列表和地图同时显示,由于地图的初始化、加载比较耗时,就想让列表先显示,地图初始化完后再显示。也就是列表显示和地图初始化同步执行,改后代码:

                    if(pageData.length>0){
                        SetListHtml(1);
                        $("#loadGif").hide();
                        setTimeout(function () {SetMap();}, 0);
                    }
                    else{
                        $("#loadGif").hide();
                    }

 

 存储过程和缓存:

       列表与地图同步可以让用户的体验好一些,但是页面加载时间还是过长,于是就把后台取数据改成存储过程、把一些不是经常改变的数据做成缓存。在做缓存的过程中,由于不是经常改变的数据有时也会改变,因此缓存依赖要设成 SqlCacheDependency 。具体方法网上有很多。

        public DataTable GetCacheGpsBoundary()
        {
            string cacheKey = "dtCustomerBoundary";
            DataTable dtCustomerBoundary = (DataTable)HttpRuntime.Cache.Get(cacheKey);
            if (dtCustomerBoundary == null)
            {
                log.Debug("dtCustomerBoundary从数据库中获取");
                dtCustomerBoundary = new DataTable();
                string sql = "";
                SqlCacheDependency sqlCacheDependency = null;
                string connectionString = ConfigurationManager.AppSettings[""];
                using (SqlConnection cn = new SqlConnection(connectionString))
                {
                    using (SqlCommand cmd = cn.CreateCommand())
                    {
                        cn.Open();
                        cmd.CommandText = sql;
                        sqlCacheDependency = new SqlCacheDependency(cmd);
                        //当有DML操作时,onChange事件会接收来自Sql Server通过sq_DispatcherProc存储过程发送给应用程序的消息。
                        using (SqlDataAdapter adapter = new SqlDataAdapter()) //查询数据
                        {
                            adapter.SelectCommand = cmd;
                            adapter.Fill(dtCustomerBoundary);
                        }
                    }
                }
                HttpContext.Current.Cache.Insert(cacheKey, dtCustomerBoundary, sqlCacheDependency);
            }
            else
            {
                log.Debug("dtCustomerBoundary从缓存中获取");
            }
            return dtCustomerBoundary;
        }
View Code

 

 GZip压缩:

       存储过程和缓存在本机测试的确加快了页面加载速度,可是发布到服务器后页面加载速度还是不理想。想分析具体原因在哪里,在网上找到一个工具:

HttpWatch Basic 9.2
Copyright: Copyright 2002 -2014 Simtec Limited
Version: 9.2.6     

先看下图例颜色的意义:

我理解 Wait 就是服务器执行用时, Receive 就是传输用时。

没有加存储过程和缓存:

再来看下改成存储过程和加缓存后

最后是启用 GZip 后的图

通过 HttpWatch 我们可以看出压缩后数据的大小 853424 ,为压缩前 4309641 的 19.80% 、用时也由 8.623 缩短到 3.119 ,由于服务器当前资源、网络情况等每次时间会有所不同。

启用 GZip 压缩后,服务器和客户端 CPU 负担会加大,但对页面加载速度效果还是很明显的,刚开始通过 HttpWatch 看出是由于传输数据过大使页面加载时间过长时,就想到要用压缩,可在后台 ajax 方法中对返回的 Json 字符串 采用 GZipStream 压缩后,在前台 JavaScript 一直找不到好的方法去解压,尝试了很多加解压算法 Zlib、LZString 等等,加解压的时间都太长了,没什么效果。

看了 单程列车 博客上 .NET MVC 简单实现GZIP  后在后台添加一个 Filter 就可以实现服务端 gzip 压缩,客户端会自动解压,客户端 ajax 时可能要加一句

headers: { "Accept-Encoding" : "gzip" } ,其实我觉得 ajax 就是异步的去打开某一网页。

 总结:

       分析、看清问题,找到问题真实原因,才有可能找到好的解决方法;

       刚开始想在取数据这块优化,看 sql 的执行计划看的一头雾水,今年要买些数据库优化方法的书补补;

       对 JavaScript、HTTP、C#、MVC、SQL 等等掌握的是否系统、全面在综合运用时起着决定性的作用

       解决一个问题的时候还是很高兴的。

 参考:

 http://stackoverflow.com/questions/5692836/maxjsonlength-exception-in-asp-net-mvc-during-javascriptserializer

http://www.cnblogs.com/zhaojingjing/archive/2011/01/20/1940357.html

http://www.cnblogs.com/willick/p/3331520.html

HTTP权威指南

 

posted on 2014-03-11 15:57  thegavincheng  阅读(981)  评论(0编辑  收藏  举报