前言
網站設計的優化是一個很大的話題,有一些通用的原則,也有針對不同開發平台的一些建議。這方面的研究一直沒有停止過,我在不同的場合也分享過這樣的話題。
作為通用的原則,雅虎的工程師團隊曾經給出過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的開發基本流程和核心技術有相當的了解,本系列文章很難對基礎知識做普及。
本文要討論的話題
這一篇我和大家討論的是第十二條原則:Remove Duplicate Scripts (刪除重復腳本)。
這條原則的意思是說,不要在一個頁面中,重復引用同一個腳本文件。乍一看起來,似乎沒有單獨拿出來談的必要:誰會這么做呢?你會嗎?我會嗎?
當然,你最好沒有這么做,而且希望你沒有這么做並不完全是出於一個好的習慣,而是因為你真的了解了重復引用同一個腳本文件所帶來的問題。
重復引用一個腳本可能存在的問題
我們可以用一個簡單的例子來看看,如果你在一個頁面中重復引用同一個腳本文件,可能存在的問題:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication1.Default" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body> <form id="form1" runat="server"> <div> <script> var count = 0; </script> <script src="JavaScript1.js"></script> <script src="JavaScript1.js"></script> <script> document.write("<h1>訪問計數:" + count + "</h1>"); </script> </div> </form> </body> </html>
頁面中,我們首先定義了一個全局的變量(count),然后重復引用了同一個腳本文件(javascript1.js),這個腳本文件內的腳本其實很簡單
count++;
這個頁面如果運行起來的話,大家可以想象一下count最后的值會是多少呢?對javascript比較熟悉的朋友一定猜出來了,由於有兩次腳本引用,所以,count的最終值應該是2。如下圖所示
所以后果是顯而易見的:我們可能認為,如果是同一個文件,引用多次的話,瀏覽器會不會聰明地只下載一次,並且也只執行一次呢?
從上圖中,我們幾乎可以覺得這就是對的,因為看起來並沒有兩個腳本請求,不是嗎?
這是一個假象!通過上面的實例,你應該會知道,實際上腳本文件肯定被下載過兩次,而且執行過兩次,否則為什么count會等於2呢?
如果你重復引用10次,那么毫無意外的,count會等於10。
好吧,我憑什么會犯這么低級的錯誤呢?你是這樣想到嗎?
This isn't as unusual as you might think. A review of the ten top U.S. web sites shows that two of them contain a duplicated script. Two main factors increase the odds of a script being duplicated in a single web page: team size and number of scripts
經研究發現,即便是美國排名前10位的網站,都可以犯這個錯。你有什么理由說你就一定不會呢?是的,有時候可能不是你一個人的錯,在一些較大的團隊和較大的項目,尤其是有大量腳本的時候,可能就要特別小心地對這些腳本進行管理了。
刪除重復腳本及最佳實踐
其實要刪除重復腳本,最重要的是要對腳本進行有效的管理,並且在編寫頁面的時候,仔細地進行引用。在ASP.NET中,善於利用一些框架,可以最大可能性地避免這個問題。
ASP.NET 從2.0開始引入了母版頁(master page)的技術,利用這個技術,我們可以將一些公用的腳本引用定義在母版頁中,而在內容頁中引入的腳本相對就少了很多了,既然很少,那么重復添加的概率就大大減小了。
下面有一個簡單范例(ASP.NET Web Forms)
<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs" Inherits="WebApplication2.SiteMaster" %> <!DOCTYPE html> <html lang="en"> <head runat="server"> <meta charset="utf-8" /> <title><%: Page.Title %> - My ASP.NET Application</title> <asp:PlaceHolder runat="server"> <%: Scripts.Render("~/bundles/modernizr") %> </asp:PlaceHolder> <webopt:BundleReference runat="server" Path="~/Content/css" /> <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" /> <meta name="viewport" content="width=device-width" /> <asp:ContentPlaceHolder runat="server" ID="HeadContent" /> </head> <body> <form runat="server"> <asp:ScriptManager runat="server"> <Scripts> <%--To learn more about bundling scripts in ScriptManager see http://go.microsoft.com/fwlink/?LinkID=272931&clcid=0x409 --%> <%--Framework Scripts--%> <asp:ScriptReference Name="MsAjaxBundle" /> <asp:ScriptReference Name="jquery" /> <asp:ScriptReference Name="jquery.ui.combined" /> <asp:ScriptReference Name="WebForms.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebForms.js" /> <asp:ScriptReference Name="WebUIValidation.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebUIValidation.js" /> <asp:ScriptReference Name="MenuStandards.js" Assembly="System.Web" Path="~/Scripts/WebForms/MenuStandards.js" /> <asp:ScriptReference Name="GridView.js" Assembly="System.Web" Path="~/Scripts/WebForms/GridView.js" /> <asp:ScriptReference Name="DetailsView.js" Assembly="System.Web" Path="~/Scripts/WebForms/DetailsView.js" /> <asp:ScriptReference Name="TreeView.js" Assembly="System.Web" Path="~/Scripts/WebForms/TreeView.js" /> <asp:ScriptReference Name="WebParts.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebParts.js" /> <asp:ScriptReference Name="Focus.js" Assembly="System.Web" Path="~/Scripts/WebForms/Focus.js" /> <asp:ScriptReference Name="WebFormsBundle" /> <%--Site Scripts--%> </Scripts> </asp:ScriptManager> <header> <div class="content-wrapper"> <div class="float-left"> <p class="site-title"> <a runat="server" href="~/">your logo here</a> </p> </div> <div class="float-right"> <section id="login"> <asp:LoginView runat="server" ViewStateMode="Disabled"> <AnonymousTemplate> <ul> <li><a id="registerLink" runat="server" href="~/Account/Register">Register</a></li> <li><a id="loginLink" runat="server" href="~/Account/Login">Log in</a></li> </ul> </AnonymousTemplate> <LoggedInTemplate> <p> Hello, <a runat="server" class="username" href="~/Account/Manage" title="Manage your account"> <asp:LoginName runat="server" CssClass="username" /></a>! <asp:LoginStatus runat="server" LogoutAction="Redirect" LogoutText="Log off" LogoutPageUrl="~/" /> </p> </LoggedInTemplate> </asp:LoginView> </section> <nav> <ul id="menu"> <li><a runat="server" href="~/">Home</a></li> <li><a runat="server" href="~/About">About</a></li> <li><a runat="server" href="~/Contact">Contact</a></li> </ul> </nav> </div> </div> </header> <div id="body"> <asp:ContentPlaceHolder runat="server" ID="FeaturedContent" /> <section class="content-wrapper main-content clear-fix"> <asp:ContentPlaceHolder runat="server" ID="MainContent" /> </section> </div> <footer> <div class="content-wrapper"> <div class="float-left"> <p>© <%: DateTime.Now.Year %> - My ASP.NET Application</p> </div> </div> </footer> </form> </body> </html>
下面還有一個ASP.NET MVC中的示例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>@ViewBag.Title - My ASP.NET MVC Application</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") </head> <body> <header> <div class="content-wrapper"> <div class="float-left"> <p class="site-title">@Html.ActionLink("your logo here", "Index", "Home")</p> </div> <div class="float-right"> <section id="login"> @Html.Partial("_LoginPartial") </section> <nav> <ul id="menu"> <li>@Html.ActionLink("Home", "Index", "Home")</li> <li>@Html.ActionLink("About", "About", "Home")</li> <li>@Html.ActionLink("Contact", "Contact", "Home")</li> </ul> </nav> </div> </div> </header> <div id="body"> @RenderSection("featured", required: false) <section class="content-wrapper main-content clear-fix"> @RenderBody() </section> </div> <footer> <div class="content-wrapper"> <div class="float-left"> <p>© @DateTime.Now.Year - My ASP.NET MVC Application</p> </div> </div> </footer> @Scripts.Render("~/bundles/jquery") @RenderSection("scripts", required: false) </body> </html>