背景

最近有一个项目是用SmartAdmin + Jquery + EasyUI 一个ASP.NET MVC5的项目,一直存在一个性能问题,加载速度比较慢,第一次加载需要(在没有cache的情况下)需要4-5秒完成全部的加载.

如下图就是用Chrome PageSpeed 测试的结果

有几个非常重要的指标

Fist Contentfu Paint:第一次绘出页面,需要4秒,前4秒都是白屏,确实有点长

Fist Meaningfull Paint:第一次绘出有意义的内容,需要8.6秒,才出现可见的操作页面.

Eliminate render-blocking resources:阻塞加载资源文件,因为的项目在head中加载了jquery和css,因为有些代码必须先执行导致的

Remove unused css:存在大量的没用的css样式定义,这也很难避免.

分析一下原因

出现上述问题的主要原因,页面本身的大小,所有资源加起来超过3.2M,Jquery EasyUI的JS+css 就接近3M,另外页面里有嵌入了好几个PartialView,还有就是执行js的时间,EasyUI DataGrid需要从后台抓起数据并生成复杂的Dom结构这都需要时间.

一般的优化手段

Cache

第一想到的就是使用cache,单只能解决第二次访问的速度问题,对少有点用,我一般会这样做,设置的方法有

  • 添加outputcache 例如:
[OutputCache(Duration = 360, VaryByParam = "none")]
public ActionResult Index() => this.View();

  • web.Config 添加对静态文件的缓存
<system.webServer><staticContent><remove fileExtension=".js" /><mimeMap fileExtension=".js" mimeType="text/javascript" /><remove fileExtension=".ico" /><mimeMap fileExtension=".ico" mimeType="image/x-icon" /><remove fileExtension=".eot" /><mimeMap fileExtension=".eot" mimeType="application/vnd.ms-fontobject" /><remove fileExtension=".woff" /><mimeMap fileExtension=".woff" mimeType="application/x-font-woff" /><remove fileExtension=".woff2" /><mimeMap fileExtension=".woff2" mimeType="application/x-font-woff2" /><remove fileExtension=".svg" /><mimeMap fileExtension=".svg" mimeType="image/svg+xml" /><remove fileExtension=".ttf" /><mimeMap fileExtension=".ttf" mimeType="application/x-font-ttf" /><clientCache cacheControlMode="UseMaxAge" httpExpires="365.00:00:00" cacheControlMaxAge="365.00:00:00" /></staticContent>
</system.webServer>

压缩和合并资源文件

尽量减少资源文件的大小和请求次数,通常的做法就是使用BundleConfig.cs合并和压缩js,css文件.我现在使用bundleconfig.json配置代替System.Web.Optimization.配置灵活一点,如果使用bundleconfig.json 编译压缩还需要解决客户端更新的缓存的问题,我使用一下代码添加一个指纹标志

public class Fingerprint{public static string Tag(string rootRelativePath){if (HttpRuntime.Cache[rootRelativePath] == null){string absolute = HostingEnvironment.MapPath("~" + rootRelativePath);DateTime date = File.GetLastWriteTime(absolute);int index = rootRelativePath.LastIndexOf('/');string result = rootRelativePath.Insert(index, "/v-" + date.Ticks);HttpRuntime.Cache.Insert(rootRelativePath, result, new CacheDependency(absolute));}return HttpRuntime.Cache[rootRelativePath] as string;}}

<system.webServer>   <urlCompression doStaticCompression="true" doDynamicCompression="true" dynamicCompressionBeforeCache="false" /><rewrite><rules><rule name="fingerprint"><match url="([\S]+)(/v-[0-9]+/)([\S]+)" /><action type="Rewrite" url="{R:1}/{R:3}" /></rule></rules></rewrite></system.webServer>

<link rel="stylesheet" href="@Fingerprint.Tag("/content/site.css")" />

ETag

ETags 是用于 Web 缓存验证的工具,允许有条件的客户端请求。通过 ETags,浏览器可以判断某项资源是否被需要。如果不需要,浏览器就不会向 Web 服务器发送请求,从而最小化请求数量。配置方法

  • 全局方案,自定义一个HttpModule
  public class ETagHttpModule : IHttpModule{#region IHttpModule Membersvoid IHttpModule.Dispose(){// Nothing to dispose; }void IHttpModule.Init(HttpApplication context){context.BeginRequest += new EventHandler(context_BeginRequest);WebPageHttpHandler.DisableWebPagesResponseHeader = true;}#endregionvoid context_BeginRequest(object sender, EventArgs e){HttpApplication app = sender as HttpApplication;//if (app.Request.CurrentExecutionFilePath.EndsWith("/") || app.Request.CurrentExecutionFilePath.EndsWith(".cshtml"))//{app.Response.Filter = new ETagStream(app.Response, app.Request);//}}#region Stream filterpublic class ETagStream : MemoryStream{private HttpResponse _response = null;private HttpRequest _request;private Stream _filter = null;public ETagStream(HttpResponse response, HttpRequest request){_response = response;_request = request;_filter = response.Filter;}private string GetToken(Stream stream){var checksum = new byte[0];checksum = MD5.Create().ComputeHash(stream);return Convert.ToBase64String(checksum, 0, checksum.Length);}public override void Write(byte[] buffer, int offset, int count){var data = new byte[count];Buffer.BlockCopy(buffer, offset, data, 0, count);var token = GetToken(new MemoryStream(data));var clientToken = _request.Headers["If-None-Match"];if (token != clientToken){_response.AddHeader("ETag", token);_filter.Write(data, 0, count);}else{_response.SuppressContent = true;_response.StatusCode = 304;_response.StatusDescription = "Not Modified";_response.AddHeader("Content-Length", "0");}}}#endregion}

<modules><remove name="FormsAuthentication" /><!--<add type="WhitespaceModule" name="WhitespaceModule" />--><add type="WebApp.ETagHttpModule" name="ETagHttpModule" />
</modules>

  • Action页面级

  

public class ETagAttribute : ActionFilterAttribute{public override void OnActionExecuting(ActionExecutingContext filterContext) => filterContext.HttpContext.Response.Filter = new ETagFilter(filterContext.HttpContext.Response, filterContext.RequestContext.HttpContext.Request);}public class ETagFilter : MemoryStream{private HttpResponseBase _response = null;private HttpRequestBase _request;private Stream _filter = null;public ETagFilter(HttpResponseBase response, HttpRequestBase request){_response = response;_request = request;_filter = response.Filter;}private string GetToken(Stream stream){var checksum = new byte[0];checksum = MD5.Create().ComputeHash(stream);return Convert.ToBase64String(checksum, 0, checksum.Length);}public override void Write(byte[] buffer, int offset, int count){var data = new byte[count];Buffer.BlockCopy(buffer, offset, data, 0, count);var token = GetToken(new MemoryStream(data));var clientToken = _request.Headers["If-None-Match"];if (token != clientToken){_response.AddHeader("ETag", token);_filter.Write(data, 0, count);}else{_response.SuppressContent = true;_response.StatusCode = 304;_response.StatusDescription = "Not Modified";_response.AddHeader("Content-Length", "0");}}}

  

//[OutputCache(Duration = 360, VaryByParam = "none")]
[ETag]
public ActionResult Index() => this.View();

效果图,回发的字节数确实减少了很多,单响应时间差不多,不是很明显.

总结

优化方案有很多,但是感觉效果都不是很理想,要做到极致的用户体验,可能真的要抛弃Jquery,EasyUI,这类肥大又复杂的类库.

问题

另外大家有没有非常好用又简单的方法解决初始加载白屏的问题,我试过用js preloading图层动画,但是效果还是不理想.但看过一些网址和APP做的效果非常好,不知道具体是如何实现的,在Asp.net mvc环境下能不能用

参考文章

(ASP.NET MVC 应用提速的十种方法)http://blog.oneapm.com/apm-tech/679.html

转载于:https://www.cnblogs.com/neozhu/p/10605929.html

ASP.NET MVC ETag Cache等优化方法相关推荐

  1. ASP.NET MVC URL重写与优化(初级篇)-使用Global路由表定制URL

    ASP.NET MVC URL重写与优化(初级篇)-使用Global路由表定制URL 引言--- 在现今搜索引擎制霸天下的时代,我们不得不做一些东西来讨好爬虫,进而提示网站的排名来博得一个看得过去的流 ...

  2. ASP.NET MVC URL重写与优化(进阶篇)-继承RouteBase玩转URL(转)

    http://www.cnblogs.com/John-Connor/archive/2012/05/03/2478821.html 引言-- 在初级篇中,我们介绍了如何利用基于ASP.NET MVC ...

  3. [转]Asp.net mvc 网站之速度优化 -- 页面缓存

    网站速度优化的一般方法 由于网站最重要的用户体验就是速度,特别是对于电子商务网站而言. 一般网站速度优化会涉及到几个方面: 1. 数据库优化 - 查询字段简历索引,使用数据库连接池和持久化,现在还有种 ...

  4. [转载]ASP.NET MVC URL重写与优化(进阶篇)-继承RouteBase玩转URL

    引言-- 在初级篇中,我们介绍了如何利用基于ASP.NET MVC的Web程序中的Global文件来简单的重写路由.也介绍了它本身的局限性-依赖于路由信息中的键值对: 如果键值对中没有的值,我们无法将 ...

  5. (转)[翻译] ASP.NET MVC Tip #1 - 使用扩展方法创建新的HTML Helper

    原文地址:http://weblogs.asp.net/stephenwalther/archive/2008/06/13/asp-net-mvc-tip-1-creating-new-html-he ...

  6. ASP.NET MVC呼叫WCF Service的方法

    本演示,Insus.NET操练asp.net mvc的应用程序,虽然以前有写过: <MVC应用程序使用Wcf Service>http://www.cnblogs.com/insus/p/ ...

  7. ASP.NET 26个常用性能优化方法

    数据库访问性能优化 数据库的连接和关闭 访问数据库资源需要创建连接.打开连接和关闭连接几个操作.这些过程需要多次与数据库交换信息以通过身份验证,比较耗费服务器资源. ASP.NET中提供了连接池(Co ...

  8. 在Asp.net MVC framework中使用扩展方法创建Html Helper

    HtmlHelper提供了一些帮助的方法返回一个字符串来生成html. 在System.Web.Mvc.Html命称空间下有一些表单,控件,局部视图Helper方法.我将创建一个生成标签<inp ...

  9. asp.net mvc 缓存CaChe使用

    缓存存储帮助类 using System; using System.Collections.Generic; using System.Linq; using System.Web; using S ...

最新文章

  1. 90.386(32位)的保护模式 (286是过渡24位) 91.什么是实模式
  2. Qt网络编程之实例一GET方式
  3. .NET Core使用NPOI导出复杂Word详解
  4. python将列表的第一列删除_python列表基本操作:索引(访问),切片,扩展,删除,追加,统计,长度,获取下标等...
  5. Flutter 项目开发指导 从基础入门到精通使用目录
  6. 长淋巴结注意事项问答
  7. PHP 还有未来么,还是 25 岁就“寿终正寝”了?
  8. iOS应用架构谈 本地持久化方案及动态部署
  9. 2014全新增强版迅捷PDF转换器介绍
  10. Oracle 数据脱敏
  11. win10系统如何设置局域网服务器地址,Win10怎么设置局域网IP地址
  12. 2020北京邮电大学计算机学院复试经验分享
  13. Bugku web — ereg正则%00截断(代码审计) ——详细题解
  14. 父进程回收子进程之wait()函数使用解读
  15. state软件的基本使用
  16. 如何正确高效使用搜索引擎
  17. Unity 之 ShaderGraph 实现旋涡(传送门)效果入门级教程
  18. 运动APP软件开发具有什么好处?
  19. 【ffmpeg】——批量合并视频
  20. (Python、mysql、机器学习与数据挖掘)小硕的自我修养进阶

热门文章

  1. 3d表情Android,像素表情3D
  2. 不懂编程,不懂设计!4个AI工具可以让任何人免费创建自己的网站 AI Website Builders
  3. pca 累积方差贡献率公式_PCA的原理及详细步骤
  4. 基于AI的5G技术-研究方向与范例-学习笔记
  5. GPIO I/O口——八种工作模式(总结)
  6. 学习 Python 爬虫,手把手通过 Python 入门爬取网页信息
  7. 上海航芯方案分享 | 针对ETC系统的OBE-SAM模块设计方案
  8. 酷毙了,Python“元宇宙”实现赛博朋克数据可视化
  9. VMware ESXi 7.0 U3k Unlocker OEM BIOS 集成网卡驱动和 NVMe 驱动 (集成驱动版)
  10. 腐烂国度1新手向MOD安装教程