統合和縮製
統合和縮製是兩種技術,您可以在 ASP.NET 4.5 中使用,以改善要求載入時間。 統合和縮減可藉由減少對伺服器的要求數目及減少要求資產的大小,來改善載入時間(例如 CSS 和 JavaScript)。
目前大部分的主要瀏覽器會將每個主機名的同時連線數目限制為六個。 這表示,雖然正在處理六個要求,但主機上資產的其他要求將會由瀏覽器排入佇列。 在下圖中,IE F12 開發人員工具網路索引標籤會顯示範例應用程式 [關於] 檢視所需的資產時機。
灰色長條會顯示要求排入佇列的時間,瀏覽器等候六個連線限制。 黃色列是第一個字節的要求時間,也就是傳送要求並接收伺服器第一個回應所花費的時間。 藍色長條會顯示從伺服器接收回應數據所花費的時間。 您可以按兩下資產以取得詳細的計時資訊。 例如,下圖顯示載入 /Scripts/MyScripts/JavaScript6.js 檔案的計時詳細數據。
上圖顯示 Start 事件,這可讓要求排入佇列的時間,因為瀏覽器會限制同時連線的數目。 在此情況下,要求已排入佇列 46 毫秒,等待另一個要求完成。
統合
統合是 ASP.NET 4.5 中的新功能,可讓您輕鬆地將多個檔案合併或組合成單一檔案。 您可以建立 CSS、JavaScript 和其他套件組合。 較少的檔案表示較少的 HTTP 要求,而且可以改善第一頁載入效能。
下圖顯示先前顯示的 [關於] 檢視的相同計時檢視,但這次已啟用統合和縮小功能。
縮小尺寸
Minification 會對腳本或 css 執行各種不同的程式碼優化,例如移除不必要的空格符和批註,並將變數名稱縮短為一個字元。 請考慮下列 JavaScript 函式。
AddAltToImg = function (imageTagAndImageID, imageContext) {
///<signature>
///<summary> Adds an alt tab to the image
// </summary>
//<param name="imgElement" type="String">The image selector.</param>
//<param name="ContextForImage" type="String">The image context.</param>
///</signature>
var imageElement = $(imageTagAndImageID, imageContext);
imageElement.attr('alt', imageElement.attr('id').replace(/ID/, ''));
}
縮減之後,函式會縮減為下列專案:
AddAltToImg = function (n, t) { var i = $(n, t); i.attr("alt", i.attr("id").replace(/ID/, "")) }
除了移除批注和不必要的空格之外,下列參數和變數名稱已重新命名(縮短),如下所示:
原始 | 重新命名 |
---|---|
imageTagAndImageID | n |
imageContext | t |
imageElement | i |
統合和縮製的影響
下表顯示個別列出所有資產,以及在範例程式中使用統合和縮製 (B/M) 之間的數個重要差異。
使用 B/M | 不含 B/M | 變更 | |
---|---|---|---|
檔案要求 | 9 | 34 | 256% |
KB 已傳送 | 3.26 | 11.92 | 266% |
已接收 KB | 388.51 | 530 | 36% |
載入時間 | 510 MS | 780 MS | 53% |
傳送的位元組大幅減少,因為瀏覽器在要求上套用的 HTTP 標頭相當詳細。 已接收的位元組縮減不會那麼大,因為已縮減最大檔案 (Scripts\jquery-ui-1.8.11.min.js 和 Scripts\jquery-1.7.1.min.js)。 注意:範例程式上的計時使用 Fiddler 工具來模擬緩慢的網路。 (來自菲德勒[規則] 功能表,選取 [效能],然後選取 [模擬調製解調器速度]。
偵錯配套和縮減的JavaScript
很容易在開發環境中對 JavaScript 進行偵錯(其中 Web.config 檔案中的編譯元素設定為 debug="true"
),因為 JavaScript 檔案並未組合或縮減。 您也可以對 JavaScript 檔案組合和縮減的發行組建進行偵錯。 使用 IE F12 開發人員工具,您可以使用下列方法來偵錯縮化套件組合中包含的 JavaScript 函式:
- 選取 [腳稿] 索引標籤,然後選取 [開始偵錯] 按鈕。
- 選取包含您想要使用 [資產] 按鈕進行偵錯的 JavaScript 函式套件組合。
- 選取 [組態] 按鈕,然後選取 [格式化 JavaScript],以格式化縮製的 JavaScript。
- 在 [ 搜尋腳本 ] 輸入方塊中,選取您要偵錯的函式名稱。 在下圖中,已在 [搜尋腳本] 輸入方塊中輸入 AddAltToImg。
如需使用 F12 開發人員工具進行偵錯的詳細資訊,請參閱 MSDN 文章 使用 F12 開發人員工具偵錯 JavaScript 錯誤。
控制統合和縮製
在 Web.config 檔案的 compilation Element 中設定偵錯屬性的值,以啟用或停用統合和縮小功能。 在下列 XML 中,設定為 true, debug
因此已停用統合和縮製。
<system.web>
<compilation debug="true" />
<!-- Lines removed for clarity. -->
</system.web>
若要啟用統合和縮製,請將 debug
值設定為 「false」。。 您可以使用 類別上的 BundleTable
屬性覆寫 Web.config 設定EnableOptimizations
。 下列程式代碼會啟用組合和縮製,並覆寫 Web.config 檔案中的任何設定。
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js"));
// Code removed for clarity.
BundleTable.EnableOptimizations = true;
}
注意
除非 EnableOptimizations
是 true
或 Web.config 檔案中編譯元素中的偵錯屬性設定為 false
,否則不會組合或縮減檔案。 此外,將不會使用 .min 版本的檔案,將會選取完整的偵錯版本。 EnableOptimizations
覆寫 Web.config 檔案中編譯元素中的偵錯屬性
搭配 ASP.NET Web Form和網頁使用統合和縮製
搭配 ASP.NET MVC 使用統合和縮製
在本節中,我們將建立 ASP.NET MVC 專案,以檢查統合和縮減。 首先,建立名為 MvcBM 的新 ASP.NET MVC因特網專案,而不變更任何預設值。
開啟 App\_Start\BundleConfig.cs 檔案,並檢查RegisterBundles
用來建立、註冊及設定套件組合的方法。 下列程式代碼顯示 方法的 RegisterBundles
一部分。
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js"));
// Code removed for clarity.
}
上述程式代碼會建立名為 ~/bundles/jquery 的新 JavaScript 套件組合,其中包含所有適當的套件組合(偵錯或縮減,但不是 。vsdoc) 腳本資料夾中符合通配符字串 “~/Scripts/jquery-{version}.js” 的檔案。 對於 ASP.NET MVC 4,這表示使用偵錯組態, 檔案jquery-1.7.1.js 將會新增至套件組合。 在發行組態中, 將會新增jquery-1.7.1.min.js 。 統合架構遵循數個常見的慣例,例如:
- 選取 「.min」 檔案,當FileX.min.js和FileX.js存在時發行。
- 選取非 “.min” 版本以進行偵錯。
- 忽略只供 IntelliSense 使用的 “-vsdoc” 檔案 (例如 jquery-1.7.1-vsdoc.js)。
{version}
上面顯示的通配符比對是用來在 Scripts 資料夾中自動建立具有適當 jQuery 版本的 jQuery 套件組合。 在此範例中,使用通配符提供下列優點:
- 可讓您使用 NuGet 更新為較新的 jQuery 版本,而不需在檢視頁面中變更先前的統合程式代碼或 jQuery 參考。
- 自動選取偵錯組態的完整版本,以及發行組建的 「.min」 版本。
使用CDN
下列程式代碼會將本機 jQuery 套件組合取代為CDN jQuery 套件組合。
public static void RegisterBundles(BundleCollection bundles)
{
//bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
// "~/Scripts/jquery-{version}.js"));
bundles.UseCdn = true; //enable CDN support
//add link to jquery on the CDN
var jqueryCdnPath = "https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js";
bundles.Add(new ScriptBundle("~/bundles/jquery",
jqueryCdnPath).Include(
"~/Scripts/jquery-{version}.js"));
// Code removed for clarity.
}
在上述程式代碼中,在發行模式中,jQuery 將會從CDN要求,而偵錯模式中的 jQuery 偵錯版本將會在本機擷取。 使用 CDN 時,如果 CDN 要求失敗,您應該會有後援機制。 配置檔案結尾的下列標記片段會顯示 CDN 失敗時新增至要求 jQuery 的腳本。
</footer>
@Scripts.Render("~/bundles/jquery")
<script type="text/javascript">
if (typeof jQuery == 'undefined') {
var e = document.createElement('script');
e.src = '@Url.Content("~/Scripts/jquery-1.7.1.js")';
e.type = 'text/javascript';
document.getElementsByTagName("head")[0].appendChild(e);
}
</script>
@RenderSection("scripts", required: false)
</body>
</html>
建立套件組合
Bundle 類別Include
方法會採用字串數位,其中每個字串都是資源的虛擬路徑。 App\_Start\BundleConfig.cs 檔案中 方法的下列程式代碼RegisterBundles
顯示如何將多個檔案新增至套件組合:
bundles.Add(new StyleBundle("~/Content/themes/base/css").Include(
"~/Content/themes/base/jquery.ui.core.css",
"~/Content/themes/base/jquery.ui.resizable.css",
"~/Content/themes/base/jquery.ui.selectable.css",
"~/Content/themes/base/jquery.ui.accordion.css",
"~/Content/themes/base/jquery.ui.autocomplete.css",
"~/Content/themes/base/jquery.ui.button.css",
"~/Content/themes/base/jquery.ui.dialog.css",
"~/Content/themes/base/jquery.ui.slider.css",
"~/Content/themes/base/jquery.ui.tabs.css",
"~/Content/themes/base/jquery.ui.datepicker.css",
"~/Content/themes/base/jquery.ui.progressbar.css",
"~/Content/themes/base/jquery.ui.theme.css"));
提供 Bundle 類別IncludeDirectory
方法以新增目錄中的所有檔案(以及選擇性地所有子目錄),以符合搜尋模式。 套件 組合 類別 IncludeDirectory
API 如下所示:
public Bundle IncludeDirectory(
string directoryVirtualPath, // The Virtual Path for the directory.
string searchPattern) // The search pattern.
public Bundle IncludeDirectory(
string directoryVirtualPath, // The Virtual Path for the directory.
string searchPattern, // The search pattern.
bool searchSubdirectories) // true to search subdirectories.
套件組合是使用 Render 方法在檢視中參考的,適用於Styles.Render
CSS 和 Scripts.Render
JavaScript。 Views\Shared\_Layout.cshtml 檔案中的下列標記顯示預設 ASP.NET 因特網項目檢視如何參考 CSS 和 JavaScript 套件組合。
<!DOCTYPE html>
<html lang="en">
<head>
@* Markup removed for clarity.*@
@Styles.Render("~/Content/themes/base/css", "~/Content/css")
@Scripts.Render("~/bundles/modernizr")
</head>
<body>
@* Markup removed for clarity.*@
@Scripts.Render("~/bundles/jquery")
@RenderSection("scripts", required: false)
</body>
</html>
請注意,Render 方法會採用字串數位列,因此您可以在一行程式代碼中新增多個套件組合。 您通常會想要使用 Render 方法,以建立必要的 HTML 來參考資產。 您可以使用 Url
方法來產生資產的 URL,而不需要參考資產的標記。 假設您想要使用新的 HTML5 異步 屬性。 下列程式代碼示範如何使用 方法參考 modernizr Url
。
<head>
@*Markup removed for clarity*@
<meta charset="utf-8" />
<title>@ViewBag.Title - MVC 4 B/M</title>
<link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<meta name="viewport" content="width=device-width" />
@Styles.Render("~/Content/css")
@* @Scripts.Render("~/bundles/modernizr")*@
<script src='@Scripts.Url("~/bundles/modernizr")' async> </script>
</head>
使用 「*」 通配符選取檔案
方法中指定的 Include
虛擬路徑和 方法中的 IncludeDirectory
搜尋模式可以接受一個 「*」 通配符做為最後一個路徑區段中的前置詞或後綴。 搜尋字串不區分大小寫。 方法 IncludeDirectory
有搜尋子目錄的選項。
請考慮具有下列 JavaScript 檔案的專案:
- Scripts\Common\AddAltToImg.js
- Scripts\Common\ToggleDiv.js
- Scripts\Common\ToggleImg.js
- Scripts\Common\Sub1\ToggleLinks.js
下表顯示使用通配符新增至套件組合的檔案,如下所示:
呼叫 | 已新增或引發例外狀況的檔案 |
---|---|
Include(“~/Scripts/Common/*.js”) | AddAltToImg.js、 ToggleDiv.js、 ToggleImg.js |
Include(“~/Scripts/Common/T*.js”) | 無效的模式例外狀況。 只有在前置詞或後綴上才允許通配符。 |
Include(“~/Scripts/Common/*og.*”) | 無效的模式例外狀況。 只允許一個通配符。 |
Include(“~/Scripts/Common/T*”) | ToggleDiv.js,ToggleImg.js |
Include(“~/Scripts/Common/*”) | 無效的模式例外狀況。 純通配符區段無效。 |
IncludeDirectory(“~/Scripts/Common”, “T*”) | ToggleDiv.js,ToggleImg.js |
IncludeDirectory(“~/Scripts/Common”, “T*”, true) | ToggleDiv.js、 ToggleImg.js、 ToggleLinks.js |
明確將每個檔案新增至套件組合通常是慣用的通配符載入檔案,原因如下:
依通配符新增文本預設會依字母順序載入它們,這通常不是您想要的。 CSS 和 JavaScript 檔案經常需要以特定(非字母順序)新增。 您可以藉由新增自定義 IBundleOrderer 實 作來減輕此風險,但明確新增每個檔案較不容易出錯。 例如,您未來可能會將新資產新增至資料夾,這可能需要您修改IBundleOrderer 實 作。
檢視使用通配符載入新增至目錄的特定檔案,可以包含在參考該配套的所有檢視中。 如果檢視特定文稿已新增至套件組合,您可能會在其他參考套件組合的檢視上收到 JavaScript 錯誤。
匯入其他檔案的 CSS 檔案會導致匯入的檔案載入兩次。 例如,下列程式代碼會建立套件組合,其中大部分的 jQuery UI 主題 CSS 檔案會載入兩次。
bundles.Add(new StyleBundle("~/jQueryUI/themes/baseAll") .IncludeDirectory("~/Content/themes/base", "*.css"));
通配符選取器 「*.css」 會帶入資料夾中的每個 CSS 檔案,包括 Content\themes\base\jquery.ui.all.css 檔案。 jquery.ui.all.css檔案會匯入其他 CSS 檔案。
套件組合快取
套件組合會在建立套件組合時,設定 HTTP 到期標頭一年。 如果您流覽至先前檢視的頁面,Fiddler 會顯示 IE 不會對套件組合提出條件式要求,也就是說,套件組合沒有來自 IE 的 HTTP GET 要求,也沒有來自伺服器的 HTTP 304 回應。 您可以強制 IE 使用 F5 金鑰為每個套件組合提出條件式要求(導致每個套件組合的 HTTP 304 回應)。 您可以使用 ^F5 強制重新整理完整重新整理(產生每個套件組合的 HTTP 200 回應。
下圖顯示 Fiddler 回應窗格的 [快取 ] 索引標籤:
要求
http://localhost/MvcBM_time/bundles/AllMyScripts?v=r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2N1PKvb81
適用於 Bundle AllMyScripts, 且包含查詢字串組 v=r0sLDicvP58AIXN\_mc3QdyVvVj5euZNzdsa2N1PKvb81。 查詢字串 v 具有值令牌,這是用於快取的唯一標識碼。 只要套件組合沒有變更,ASP.NET 應用程式就會使用此令牌要求 AllMyScripts 套件組合。 如果套件組合中的任何檔案變更,ASP.NET 優化架構將會產生新的令牌,以確保套件組合的瀏覽器要求會取得最新的套件組合。
如果您執行 IE9 F12 開發人員工具並流覽至先前載入的頁面,IE 會錯誤地顯示對每個套件組合提出的條件式 GET 要求,以及傳回 HTTP 304 的伺服器。 您可以閱讀為什麼 IE9 在部落格文章 使用 CDN 和到期以改善網站效能時判斷是否有條件式要求時發生問題。
LESS、CoffeeScript、SCSS、Sass 統合。
統合和縮製架構提供一種機制,可處理 SCSS、Sass、LESS 或 Coffeescript 等中繼語言,並將縮減之類的轉換套用至產生的套件組合。 例如,若要將 .less 檔案新增至 MVC 4 專案:
為您的 LESS 內容建立資料夾。 下列範例使用 Content\MyLess 資料夾。
將 .less NuGet 套件 無 點新增至您的專案。
新增實作 IBundleTransform 介面的類別。 針對 .less 轉換,將下列程式代碼新增至您的專案。
using System.Web.Optimization; public class LessTransform : IBundleTransform { public void Process(BundleContext context, BundleResponse response) { response.Content = dotless.Core.Less.Parse(response.Content); response.ContentType = "text/css"; } }
使用和 CssMinify 轉換建立 LESS 檔案
LessTransform
組合。 將下列程式代碼新增至RegisterBundles
App\_Start\BundleConfig.cs 檔案中的 方法。var lessBundle = new Bundle("~/My/Less").IncludeDirectory("~/My", "*.less"); lessBundle.Transforms.Add(new LessTransform()); lessBundle.Transforms.Add(new CssMinify()); bundles.Add(lessBundle);
將下列程式代碼新增至任何參考 LESS 套件組合的檢視。
@Styles.Render("~/My/Less");
套件組合考慮
建立套件組合時要遵循的良好慣例,就是在套件組合名稱中包含“bundle” 作為前置詞。 這可防止可能的 路由衝突。
更新套件組合中的一個檔案之後,套件組合查詢字串參數會產生新的令牌,而且下次用戶端要求包含套件組合的頁面時,必須下載完整的套件組合。 在個別列出每個資產的傳統標記中,只會下載已變更的檔案。 經常變更的資產可能不是組合的好候選專案。
統合和縮製主要改善的是第一頁要求載入時間。 要求網頁之後,瀏覽器會快取資產(JavaScript、CSS 和影像),因此在要求相同頁面或要求相同資產的相同網站上頁面時,統合和縮減不會提供任何效能提升。 如果您未在資產上正確設定到期標頭,且未使用統合和縮製,瀏覽器的新鮮啟發學習法會在幾天后將資產標示為過時,且瀏覽器需要每個資產的驗證要求。 在此情況下,統合和縮減會在第一頁要求之後提供效能提升。 如需詳細資訊,請參閱使用CDN和到期以改善網站效能的部落格。
每個主機名同時連線的瀏覽器限制可藉由使用 CDN來減輕。 由於 CDN 的主機名與主控網站不同,因此來自 CDN 的資產要求不會計入裝載環境的六個同時連線限制。 CDN 也可以提供常見的套件快取和邊緣快取優點。
套件組合應該依需要它們的頁面進行分割。 例如,因特網應用程式的預設 ASP.NET MVC 範本會建立與 jQuery 不同的 jQuery 驗證套件組合。 由於建立的默認檢視沒有輸入,而且不會張貼值,因此不包含驗證套件組合。
命名空間 System.Web.Optimization
會在 System.Web.Optimization.dll 中 實作。 它會利用 WebGrease 連結庫 (WebGrease.dll) 進行縮製功能,進而使用 Antlr3.Runtime.dll。
我使用 Twitter 製作快速文章並分享連結。 我的 Twitter 句柄是: @RickAndMSFT
其他資源
- 影片:霍華德·迪爾金的統合和優化
- 將 Web 優化新增至網頁網站。
- 將統合和縮製新增至 Web Form。
- Henrik F Nielsen @frystyk
- 使用 CDN 和到期來改善 Rick Anderson 的網站效能@RickAndMSFT
- 最小化 RTT (往返時間)
參與者
- 浩功
- 霍華德·迪爾金
- 戴安娜·拉羅斯