这个系列是,基础学习系列的最后一部分,这里,我打算翻译一篇国外的技术文章结束这个基础部分的学习;后面打算继续写深入学习MVC系列的文章,之所以要写博客,我个人觉得,做技术的,首先得要懂得分享,说不定你自己以为正确的东西,存在瑕疵,分享出来,大家也可以互相进步。这样整个生态圈也会越来越好。不是么? 好了,闲话扯远了,下面开始正题吧,一下是英文和中文对照,翻译的不好,请见谅。
This article introduces how to improve ASP.NET MVC Application performance with the help of bundling and minification. Both bundling and minification are the two separate techniques to reduce the load time. The bundling reduces the number of requests to the Server, while the minification reduces the size of the requested assets.
这篇文章介绍了使用捆绑和压缩技术来提高ASP.NET MVC 程序的性能。捆绑个压缩是两个单独的技术,用来减少程序加载的时间。捆绑减少了向服务器请求的数量,压缩减小了文件【js,css等】的大小。
Most browsers process six requests simultaneously【[,sɪml'teɪnɪəslɪ]】【adv.同时地】 to each Website, which is why additional requests will be queued【v.排队】 by the Browsers. If we reduce these requests, the queued time for the other requests will be reduced as well. Thus, bundling is used to reduce these requests from the Browser to Server.
大多数的浏览器同时处理向网站处理6个请求,这也就是多余的请求,会被浏览器要求排队等待的原因。如果我们减少这些请求数,其他的请求等待的时间将会缩短。所以捆绑是用来减少向服务器发送请求的数量的。【PS:这里你可能会有疑问,怎么减少呢?别着急,后面慢慢看。。。】
The minification【压缩】 is the removal【n.排除】【 [rɪ'muːv(ə)l]】 of all unnecessary characters from a text-based resource (JS and CSS) in a way that doesn’t alter the expected functionality. This means shortening【 ['ʃɔːt(ə)nɪŋ]】【n.缩短】 identifiers, aliasing functions and removing the comments, white-space characters and new lines.
压缩技术移除了资源文件【js和css】中不必要的字符数【通过移除不必要的注释,空白字符,和换行】,并不会影响js,和css所要实现的功能。
Both bundling and minification can be applied together but both have a separate process. As the minified and bundling version is hard to read and step through, we should not bundle and minify all CSS and JS files at a time of production or debug, while we must do bundling and minification of all the files, when we go live.
捆绑和压缩可以同时应用到程序中,但是它们有一个单独的处理过程。因为经过捆绑压缩的版本很难阅读它的代码,不方便调试错误。所以,在生产或者Debug情况下,我们不应该同时捆绑和压缩所以的css和js文件。而是应该根据需要选择性的来捆绑个压缩。
The ASP.NETMVC offers bundling and minification technique by System.Web.Optimization class, which exists under the System.Web.Optimization dll.
APS.NET MVC 捆绑个压缩技术是在 System.Web.Optimization 类中提供的。这个类在 System.Web.Optimization dll.下
Bundling【捆绑】
The bundle is a logical group of physical files, which loads in a single HTTP request. We have separate CSS files, which can be loaded in a single request with the help of bundling. The bundling also can create for JavaScript files separately.A bundle can’t contain both CSS and JavaScript files. We need to create a separate bundle for CSS and JavaScript files. We create a bundle, based on the use of CSS or JS files in the Application. For example, an Application uses both the bootstrap and site CSS for UI design, due to which we create a common bundle for them, such as a core bundle. The following figure shows a logical grouping of a file to create a bundle.
捆绑是逻辑的分组物理文件,最终把多个文件,合并到一个文件,只提交一个HTTP请求,例如,我们可以使用捆绑,来捆绑多个css文件,最终在浏览器中,将会是一个单独的请求。捆绑,同样也可以应用于多个js文件。但是,请注意,一个捆绑不能同时包含css和jsw文件,我们需要为css文件和js文件单独的捆绑。例如,一个应用程序,同时为页面使用Bootstrap和site.css文件,这个时候,我们就可以创建一个公共的捆绑。这样就把多个css文件,合并成了一个css文件。
我们先看看捆绑技术吧:
新建一个MVC web项目,模板选择MVC,【PS:如果选择空白的模板的话,就需要自己,添加一堆的文件。】
这个MVC模板,自动为我们引入了捆绑和压缩技术需要的文件和DLL等东西。
我们先看下BundleConfig类:
using System.Web;
using System.Web.Optimization; namespace WebApplication7
{
public class BundleConfig
{
// 有关绑定的详细信息,请访问 http://go.microsoft.com/fwlink/?LinkId=301862
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js")); bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.validate*")); // 使用要用于开发和学习的 Modernizr 的开发版本。然后,当你做好
// 生产准备时,请使用 http://modernizr.com 上的生成工具来仅选择所需的测试。
bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
"~/Scripts/modernizr-*")); bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
"~/Scripts/bootstrap.js",
"~/Scripts/respond.js")); bundles.Add(new StyleBundle("~/Content/css").Include(
"~/Content/bootstrap.css",
"~/Content/site.css")); // 将 EnableOptimizations 设为 false 以进行调试。有关详细信息,
// 请访问 http://go.microsoft.com/fwlink/?LinkId=301862
BundleTable.EnableOptimizations = true;
}
}
}
BundleConfig类,是用来创建Script Bundle和Style Bundle的。上面标红色的代码示例是,捆绑Bootstrap的css文件和site.CSS文件。Bundle name是一个虚拟的文件名,【ps:这里标红色的代码的bundle name是~/Content/css】,里面是要包含要捆绑的文件路径,强烈建议,不要将bundle name和文件路径名字弄成一样的。
另外绑定和捆绑,是在Global文件中注册的,我们看下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing; namespace WebApplication7
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
}
我们不需要,为每一个捆绑都注册,只要在里面加上这句话就可以了: BundleConfig.RegisterBundles(BundleTable.Bundles);
对于刚才那个绑定,然后在视图中调用这句代码就可以了,【PS,我们使用默认的MVC模板,是默认启用了捆绑和压缩的。】
@Styles.Render("~/Content/css")
捆绑和压缩的技术的启用:
The bundle doesn’t work in the debug mode. Thus, we set the debug value false in web.config file, as shown in the snippet, given below:
捆绑不能在Debug模式下工作,所以我们第一种启用捆绑的方式是修改位置文件,把dubug模式改为false,例如下面这样,就可以启用捆绑技术了。
- <system.web>
- <compilation debug="false" targetFramework="4.5.1" />
- <httpRuntime targetFramework="4.5.1" />
- </system.web>
第二种启用捆绑的方式是,配置文件bebug还是设置为true,不用管它,在BundleConfig类中加上这句话: BundleTable.EnableOptimizations = true;【PS这句话,是我们使用MVC模板,创建项目的时候,自动为我们加上的】。
using System.Web;
using System.Web.Optimization; namespace WebApplication7
{
public class BundleConfig
{
// 有关绑定的详细信息,请访问 http://go.microsoft.com/fwlink/?LinkId=301862
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js")); bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.validate*")); // 使用要用于开发和学习的 Modernizr 的开发版本。然后,当你做好
// 生产准备时,请使用 http://modernizr.com 上的生成工具来仅选择所需的测试。
bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
"~/Scripts/modernizr-*")); bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
"~/Scripts/bootstrap.js",
"~/Scripts/respond.js")); bundles.Add(new StyleBundle("~/Content/css").Include(
"~/Content/bootstrap.css",
"~/Content/site.css")); // 将 EnableOptimizations 设为 false 以进行调试。有关详细信息,
// 请访问 http://go.microsoft.com/fwlink/?LinkId=301862
BundleTable.EnableOptimizations = true;
}
}
}
好了,说了这么多,我们 看下MVC默认的项目,实现的捆绑是咋样的吧,直接运行项目:然后按F12打开调试工具:
从调试工具中,我们看到了总共有6个请求,css文件和js文件都被压缩了,加载总共耗时357ms,这是怎么做到的呢????
我们看下布局页【layout】
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewBag.Title - 我的 ASP.NET 应用程序</title>
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr") </head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
@Html.ActionLink("应用程序名称", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>@Html.ActionLink("主页", "Index", "Home")</li>
<li>@Html.ActionLink("关于", "About", "Home")</li>
<li>@Html.ActionLink("联系方式", "Contact", "Home")</li>
</ul>
@Html.Partial("_LoginPartial")
</div>
</div>
</div>
<div class="container body-content">
@RenderBody()
<hr />
<footer>
<p>© @DateTime.Now.Year - 我的 ASP.NET 应用程序</p>
</footer>
</div> @Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@RenderSection("scripts", required: false)
</body>
</html>
布局页中,这几句代码,调用了BundleConfig类文件中的bundle name,然后就实现了捆绑了。
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
好了,如果说上面是系统自动为我们创建的捆绑,那么我们现在自己来修改一下,添加一个css文件,并修改bundle name实现捆绑:
我们在Content文件夹下,添加一个属于自己的css文件,在里面写几句测试代码:
然后,我将自己写的css文件,添加捆绑:【注意这里我修改了bundle name】
然后在布局页里做相应的修改:
然后运行项目:
可以看到我们自己写的css样式起作用了,我们按下F12看下情况:
看到了么,这里的名字就变成我们自定义的名字了【CFScss】。
好了,这里是启用捆绑的情况,我们如果不想用捆绑呢,上面说到了,有两种方式可以做到,我们看看不使用捆绑的情况:
修改BundleConfig类中的代码:改为false就可以了,配置文件不用管。这是最方便的方式,我个人认为。然后运行项目:
可以看到不使用捆绑的话,我们的css,js文件都是要一个一个的加载的。这里的请求数就是9了,加载时间也边长了。。【这是本地测试,而且浏览器有缓存】。
好了,既然是翻译当然也不能光翻译,还是需要理论和实践相结合。里面的代码都是自己写的例子。
In the same way, we can also create a bundle for the script, which is called Script bundle. For example, we create a bundle for bootstrap JS file as per the code snippet, given below, which defined in RegisterBundles method of BundleConfig class. We can add multiple files path in a bundle, which will be separated by a comma.
同样,我们可以创建Script Bundle,例如下面的代码:
- bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
- "~/Scripts/bootstrap.js"));
We can also define the versioning in the bundle. The code, given below, shows that it always loads the latest version of jQuery file.
我们同样可以定义绑定的版本,下面的代码将会使用获取到最新版本的Jquery文件。
- bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
- "~/Scripts/jquery-{version}.js"));
We can also combine the files that are in the same folder and have the same prefix or suffix with its name.Suppose we want to add all the script files, that exist within “~/Scripts” folder and have “jquery.validate” as a prefix, then we can create bundle as per code snippet, given below:
我们同样可以定义在同一个文件夹下的文件有项目的前缀和后缀,例如,下面的代码表示:在“~/Script”文件夹下,所有的文件都是以“Jquery.validation”开头。
- bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include( "~/Scripts/jquery.validate*"));
Now, call this script bundle on the view as per the code snippet, given below:
在程序中我们这样调用:
- @Scripts.Render("~/bundles/jquery")
Now, run the Application and see that all the JS files are converted to a single JS file, as shown below:
现在运行,我们可以看到所有的JS文件都转化成了一个单一的js文件
- <script src="/bundles/jquery?v=FVs3ACwOLIVInrAl5sdzR2jrCDmVOWFbZMY6g6Q0ulE1"></script>
当然为了提高性能,我们还可以从CDN加载资源,
我们来试试:
修改BundleConfig类中的代码:
using System.Web;
using System.Web.Optimization; namespace WebApplication7
{
public class BundleConfig
{
// 有关绑定的详细信息,请访问 http://go.microsoft.com/fwlink/?LinkId=301862
public static void RegisterBundles(BundleCollection bundles)
{
bundles.UseCdn = true;
bundles.Add(new ScriptBundle("~/CFS/wahahaJquery", "http://libs.baidu.com/jquery/2.0.0/jquery.min.js")); //bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
// "~/Scripts/jquery-{version}.js")); bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.CFSvalidate*")); // 使用要用于开发和学习的 Modernizr 的开发版本。然后,当你做好
// 生产准备时,请使用 http://modernizr.com 上的生成工具来仅选择所需的测试。
bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
"~/Scripts/modernizr-*")); bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
"~/Scripts/bootstrap.js",
"~/Scripts/respond.js")); bundles.Add(new StyleBundle("~/Content/CFScss").Include(
"~/Content/bootstrap.css",
"~/Content/site.css","~/Content/cfs.css")); // 将 EnableOptimizations 设为 false 以进行调试。有关详细信息,
// 请访问 http://go.microsoft.com/fwlink/?LinkId=301862
BundleTable.EnableOptimizations = true;
}
}
}
然后,修改对应的布局页:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewBag.Title - 我的 ASP.NET 应用程序</title>
@Styles.Render("~/Content/CFScss")
@Scripts.Render("~/bundles/modernizr") </head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
@Html.ActionLink("应用程序名称", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>@Html.ActionLink("主页", "Index", "Home")</li>
<li>@Html.ActionLink("关于", "About", "Home")</li>
<li>@Html.ActionLink("联系方式", "Contact", "Home")</li>
</ul>
@Html.Partial("_LoginPartial")
</div>
</div>
</div>
<div class="container body-content">
@RenderBody()
<hr />
<footer>
<p>© @DateTime.Now.Year - 我的 ASP.NET 应用程序</p>
</footer>
</div> @Scripts.Render("~/CFS/wahahaJquery")
@Scripts.Render("~/bundles/bootstrap")
@RenderSection("scripts", required: false)
</body>
</html>
运行程序,可以看到,J使用CDN加载query文件,没有被压缩捆绑
The CDN stands for Content Delivery Networks are the Servers, where the latest jQuery libraries are hosted like Google, Cloud Flare etc. The CDN helps to access or download the files, parallel to the files downloaded from our own Website and will be cached the first time. Sometimes, these CDN hosted files are not good for our Websites, because there are some issues like performances due to slow CDN Servers, even non-availability of the Servers etc.
CDN代表内容分发网络,在这里,最新的Jquery文件被宿主像谷歌,Cloud Flare等等。CDN帮助我们去获取下载对应的资源文件。然后把文件融合进我们的网站里面,CDN加载资源文件,第一次的时候,会被浏览器缓存,但是有时候,CDN加载文件,并不是非常好的做法,因为它们有时候会出现性能问题,例如CDN服务器崩溃了。
为了解决这个问题,我们可以在程序中,手动加上下面的代码,这样在CDN服务器崩溃的时候,我们加载我们本地的资源文件:
@Scripts.Render("~/bundles/jquery")
<script type = "text/javascript" >
if (typeof jQuery == 'undefined')
{
var script = document.createElement('script');
script.src = '@Url.Content("~/Scripts/jquery-1.10.2.js")';
script.type = 'text/javascript';
document.getElementsByTagName("head")[0].appendChild(script);
}
</script>
上面,说了这么多捆绑的技术,现在说说压缩的技术:
The Minification is a technique for removing unnecessary characters (white space, newline, tab), comments and short variable names from the text based files such as JavaScript and CSS files without expecting alter functionality to reduce the size, which causes improved load times of a Webpage. There are some tools available to minify JS and CSS files. We can download Visual Studio extension from link for minifying JS and CSS files.
这个压缩的技术是移除js和css文件中不必要的空白,换行,tab,注释,但不会影响功能。只会减小文件的大小。所以也就提交了页面加载资源的速度,节省了时间。这里有一些压缩js。css的工具,点击链接进去就是了。
Busting Browser's Cache by Bundling【破坏浏览器的缓存】
As we upload the changes in the static resources such as CSS and JS files on the live server, the resources changes but it does not update on the Browser, because the Browser's cache resources are based on URLs automatically.Thus, when a Web page requests a resource, it checks in cache first. If the resource is found in cache, use cached copy rather than retrieving the resources from the Server. Hence, whenever you change the content of CSS and JS, files will not reflect on the Browser. For this, you need to force the Browser for refreshing/reloading.
当我们上传的讲台文件发生改变的时候,这个改变在浏览器中不会更新,是因为浏览器有缓存,浏览器是基于URL自动缓存的。所以,当一个页面请求一个资源的时候,浏览器会首先,检查一下浏览器缓存,如果资源在缓存在存在,那么浏览器就会直接使用缓存,而不是从服务器再去请求资源文件,所以,不管什么时候你改变css和js文件的时候,改变不会立刻反应在浏览器中的时候,你就需要去强制刷新浏览器了,以重新加载。
The bundles set the HTTP expires header, one year from when the bundle is created. As we have a CSS bundle resource, which loads on the Browser with the following link.
这个bundle设置了HTTP过期的表头,只要bundle创建了,我们在浏览器中看到的就是下面的情况,而不是单个的css,js文件。
- <link href="/Content/css?v=Bz3KZjU_pdOm2wAVr7z_ylCuQzQDs1O8N6pV4cvXc_Q1" rel="stylesheet"/>
The /Content/css style bundle contains the query string pair v=Bz3KZjU_pdOm2wAVr7z_ylCuQzQDs1O8N6pV4cvXc_Q1. The query string v has a value token. This token is a unique identifier, which is used for caching. As long as the bundle /Content/css dosen’t change, the request for this bundle uses its same token. If any file in the bundle changes, ASP.NET optimization framework will generate a new token, guaranteeing the browser requests for the bundle will get the latest bundle.
这个bundle包含了QueryString v=Bz3KZjU_pdOm2wAVr7z_ylCuQzQDs1O8N6pV4cvXc_Q1,这个v值就是一个令牌。被用来做缓存。只要你绑定中的资源文件,没有被修改的话,这个值就不会被改变。相反,如果你的资源文件中发生改变了,ASP.NET Optimization框架就会自动为我们生成一个新的令牌,来确保浏览器请求的资源都是最新的。这也就达到了自动刷新,不用我们手动刷新了。
We create bundling to improve an Application's performance, while it works in the release mode only but we develop an Application in the debug mode on our machine. Thus, we create a unique token for the resource path. We add a version key in the web.config, which will be used as a unique token in the development.
我们创建的bundle只能在release模式下运行,这个时候,我们可以为资源路径,创建一个唯一的令牌,在配置文件中,我们加上这句话:
<appSettings>
<add key="Version" value="sa291988" />
</appSettings>
Afterwards, create a class, where we define the format for both JavaScript and styles. The code snippet is given below for the same.
然后,我们创建一个类,定义js和css的格式:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Configuration; namespace WebApplication7.App_Start
{
public class BundleSample
{
public static string StyleVersion
{
get
{
return "<link href=\"{0}?v=" + ConfigurationManager.AppSettings["Version"] + "\"rel=\"stylesheet\"/ >";
}
} public static string ScriptVersion
{
get
{
return "<script src=\"{0}?v=" + ConfigurationManager.AppSettings["Version"] + "\"></script>";
}
}
}
}
然后在layout中这样用:
Now, render JS and CSS files on the views in the following ways.
- @Styles.RenderFormat(SiteKeys.StyleVersion,"~/Content/css")
- @Scripts.RenderFormat(SiteKeys.ScriptVersion,"~/bundles/jquery")
These techniques help to improve the Application's performance.
这些技术是用来提高系统的性能的。
修改Layout,我们运行项目看下
@using WebApplication7.App_Start
<!DOCTYPE html>
<html>
<head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewBag.Title - 我的 ASP.NET 应用程序</title>
@*@Styles.Render("~/Content/CFScss")*@
@Styles.RenderFormat(BundleSample.StyleVersion, "~/Content/CFScss")
@Scripts.Render("~/bundles/modernizr") </head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
@Html.ActionLink("应用程序名称", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>@Html.ActionLink("主页", "Index", "Home")</li>
<li>@Html.ActionLink("关于", "About", "Home")</li>
<li>@Html.ActionLink("联系方式", "Contact", "Home")</li>
</ul>
@Html.Partial("_LoginPartial")
</div>
</div>
</div>
<div class="container body-content">
@RenderBody()
<hr />
<footer>
<p>© @DateTime.Now.Year - 我的 ASP.NET 应用程序</p>
</footer>
</div> @Scripts.Render("~/CFS/wahahaJquery")
@Scripts.Render("~/bundles/bootstrap")
@RenderSection("scripts", required: false)
</body>
</html>
看到了么,我们自己添加的版本号就在这了。。。好了,这就是MVC中的捆绑和压缩,翻译真是件苦差事,昨天看英文自己学一遍,今天自己翻译在学一遍,翻译不好,大家指正,谢谢了。。。