前言
網站設計的優化是一個很大的話題,有一些通用的原則,也有針對不同開發平台的一些建議。這方面的研究一直沒有停止過,我在不同的場合也分享過這樣的話題。
作為通用的原則,雅虎的工程師團隊曾經給出過35個最佳實踐。這個列表請參考
Best Practices for Speeding Up Your Web Site http://developer.yahoo.com/performance/rules.html
同時,他們還發布了一個相應的測試工具Yslow http://developer.yahoo.com/yslow/
我強烈推薦所有的網站開發人員都應該學習這些最佳實踐,並結合自己的實際項目情況進行應用。
接下來的一段時間,我將結合ASP.NET這個開發平台,針對這些原則,通過一個系列文章的形式,做些講解和演繹,以幫助大家更好地理解這些原則,並且更好地使用他們。
准備工作
為了跟隨我進行后續的學習,你需要准備如下的開發環境和工具
- Google Chrome 或者firefox ,並且安裝 Yslow這個擴展組件.請注意,這個組件是雅虎提供的,但目前沒有針對IE的版本。
- https://chrome.google.com/webstore/detail/yslow/ninejjcohidippngpapiilnmkgllmakh
- https://addons.mozilla.org/en-US/firefox/addon/yslow/
- 你應該對這些瀏覽器的開發人員工具有所了解,你可以通過按下F12鍵調出這個工具。
- Visaul Studio 2010 SP1 或更高版本,推薦使用Visual Studio 2012
- 你需要對ASP.NET的開發基本流程和核心技術有相當的了解,本系列文章很難對基礎知識做普及。
本文要討論的話題
這一篇文章討論的是第一個原則:應該盡可能加減少請求數。這個原則的說明請參考 http://developer.yahoo.com/performance/rules.html#num_http
我們的網頁在加載的時候,為了提供更加豐富的內容和效果,除了頁面本身這個請求之外,總是需要加載其他一些資源的,例如我們常見的Javascript文件,css文件,圖片,甚至還會有一些Flash組件等等。這本無可厚非,但如果過多的外部請求,會很直接地降低頁面加載的速度。
我們來看一個例子吧。例如我們經常訪問的博客園的首頁
這個網頁的加載需要多少次請求呢?(如果不考慮緩存的話)
我們看到,請求數為55個。我們進一步通過Yslow來分析,可以得到綜合的報表
應該說博客園的設計已經比較注意很多細節了。他們得到了B級的評分。我們再來看看其他一些主要的門戶的表現吧(從左至右,依次是新浪,搜狐,騰訊,淘寶),他們都只得到D級的評分。
【備注】這些評分只是作為一個參考,不做任何的結論和推論。
如何減少請求數?
我們可以通過如下的幾個方法來減少請求數:
- 合並外部資源文件(如javascript,css,圖片文件)
- 圖片的合並,是將多個圖片合並為一個圖片,然后采用css的一些設置(background-image,background-position) 來使用它們。這個很簡單實用(但是效果也是顯著的)。本文將不做演示。
- javascript和css文件的合並,這個可能大家不太經常注意到。本文的后續部分將對此進行演示。
- 使用Inline images 這種方式. 這個方式可能依賴於瀏覽器的實現,目前並不是所有的瀏覽器都支持。所以本文也不做演示。
合並javascript文件和css文件
對於這兩種文件的合並而言,我們當然可以手工去做(copy,paste),把一個文件的內容粘貼在另外一個文件內容的底部即可。但這種方式有幾個缺點:
- 破壞了原有文件的結構
- 不同頁面需要的文件組合可能是不一樣的,這種情況下會需要產生多個不同的文件,而且需要比較小心地維護它們
- 如果文件的內容發生變化,就需要重新再來一次
所以,我並不是很推薦用這種手工合並的方法,事實上,我們有更好的工具來實現, 並且在ASP.NET的一些框架(例如ASP.NET MVC)里面已經有了內置的實現。
我們先來看一個例子,下面是一個典型的ASP.NET MVC項目
我找了其中的一個用戶注冊頁面,在IE中進行查看
我們看到默認情況下,完成這個頁面其實要執行8個請求。但經過簡單的處理(添加一行代碼)之后,我們可以看到如下的效果
而且如果你細心看的話,在這個頁面中請求的javascript文件似乎看起來經過了特殊的處理(路徑比較特殊)。那么,這是如何實現的呢?
原來,在MVC項目中,默認會有一個所謂的BundleConfig的類,它提供了一個方法RegisterBundles,如下所示
using System.Web; using System.Web.Optimization; namespace MvcApplication1 { public class BundleConfig { // For more information on Bundling, visit http://go.microsoft.com/fwlink/?LinkId=254725 public static void RegisterBundles(BundleCollection bundles) { bundles.Add(new ScriptBundle("~/bundles/jquery").Include( "~/Scripts/jquery-{version}.js")); bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include( "~/Scripts/jquery-ui-{version}.js")); bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include( "~/Scripts/jquery.unobtrusive*", "~/Scripts/jquery.validate*")); // Use the development version of Modernizr to develop with and learn from. Then, when you're // ready for production, use the build tool at http://modernizr.com to pick only the tests you need. bundles.Add(new ScriptBundle("~/bundles/modernizr").Include( "~/Scripts/modernizr-*")); bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css")); 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")); } } }
這個方法會在Global.asax文件中調用
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Http; using System.Web.Mvc; using System.Web.Optimization; using System.Web.Routing; namespace MvcApplication1 { // Note: For instructions on enabling IIS6 or IIS7 classic mode, // visit http://go.microsoft.com/?LinkId=9394801 public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); //BundleTable.EnableOptimizations = false;//啟用這一行,則使用Bundle的機制進行文件打包 AuthConfig.RegisterAuth(); } } }
在具體的頁面中,如果需要用到上述的腳本組合,則可以使用下面這樣的語法來調用
@Scripts.Render("~/bundles/jqueryval")
這就是所有的秘密。
那么,這個技術是不是只能使用在MVC中,在我們另外一種開發框架(ASP.NET Web Forms)中是否也可以使用呢?
答案是:可以的。而且這個技術,確實是最早就是用在ASP.NET Web Forms里面,只不過,因為這方面的文檔較少,所以可能大家用的不多而已。下面是我作為演示用的一個簡單的ASP.NET Web Forms的項目:
我們看到,在頁面中,我們添加了三個腳本引用,這樣的話,自然在打開頁面的時候,需要單獨請求這三個腳本文件。
我們是否可以將這三個文件合並成一個請求呢?請跟隨我來進行如下的操作
首先,添加一個組件,這是微軟官方發布的System.Web.Optimization,顧名思義,這就是為了優化網絡開發用的
按照一般的慣例,我們在項目中添加一個文件,來進行Bundle的注冊
using System.Web.Optimization; namespace WebApplication1 { public class BundleConfig { public static void RegisterBundle(BundleCollection config) { config.Add(new ScriptBundle("~/default").Include("~/scripts/jquery-2.0.0.min.js", "~/scripts/knockout-2.2.1.js", "~/default.js")); } } }
然后,我們修改Global.asax文件,添加如下的代碼
using System; using System.Web.Optimization; namespace WebApplication1 { public class Global : System.Web.HttpApplication { protected void Application_Start(object sender, EventArgs e) { BundleConfig.RegisterBundle(BundleTable.Bundles); BundleTable.EnableOptimizations = true; } } }
最后,我們在頁面上也做相應的修改,如下所示(請注意粗體部分)
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication1.Default" %> <%@ Import Namespace="System.Web.Optimization" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> <%= Scripts.Render("~/default") %> </head> <body> <form id="form1" runat="server"> <div> </div> </form> </body> </html>
很不錯,我們現在可以查看一下頁面運行起來的效果
很明顯,原先的三個請求,現在變成了一個請求。需要注意的是,如果我們去計算文件大小,這個合並之后的文件,體積會比之前三個文件體積總和略小一些。所以你可以理解為這里存在一定的壓縮,但這個壓縮比是不大的(尤其是原有的javascript文件本身就經過了壓縮的情況下)。關於javascript文件或者css文件的壓縮,后續會有專門的文章介紹。
上面的例子,演示的是javascript文件的合並。其實,css文件的合並也是類似的做法,區別在於要使用StyleBundle : http://msdn.microsoft.com/en-us/library/system.web.optimization.stylebundle.aspx
總結
本文介紹了網站優化的第一個原則(盡量減少請求數),我帶領大家分析了為什么需要考慮這個原則,以及具體如何實現(包括在MVC和Web Forms的做法)