這個系列是,基礎學習系列的最後一部分,這裡,我打算翻譯一篇國外的技術文章結束這個基礎部分的學習;後面打算繼續寫深入學習MVC系列的文章,之所以要寫博客,我個人覺得,做技術的,首先得要懂得分享,說不定你自己以為正確的東西,存在瑕疵,分享出來,大家也可以互相進步。這樣整個生態圈也會越來越好。不是麽? 好 ...
這個系列是,基礎學習系列的最後一部分,這裡,我打算翻譯一篇國外的技術文章結束這個基礎部分的學習;後面打算繼續寫深入學習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="