新聞資訊

網站頁面性能優化的(de)20條黃金守則

1、用<link>代替@import

前面的(de)最佳實現中提到(dào)CSS應該放置在(zài)頂端以(yǐ)利于(yú)有序加載呈現。      

在(zài)IE中,頁面底部@import和(hé / huò)使用

作用是(shì)一(yī / yì /yí)樣的(de),因此最好不(bù)要(yào / yāo)使用它。


2、避免使用濾鏡      

IE獨有屬性AlphaImageLoader用于(yú)修正7.0以(yǐ)下版本中顯示PNG圖片的(de)半透明效果。這(zhè)個(gè)濾鏡的(de)問題在(zài)于(yú)浏覽器加載圖片時(shí)它會終止内容的(de)呈現并且凍結浏覽器。在(zài)每一(yī / yì /yí)個(gè)元素(不(bù)僅僅是(shì)圖片)它都會運算一(yī / yì /yí)次,增加了(le/liǎo)内存開支,因此它的(de)問題是(shì)多方面的(de)。      

完全避免使用AlphaImageLoader的(de)最好方法就(jiù)是(shì)使用PNG8格式來(lái)代替,這(zhè)種格式能在(zài)IE中很好地(dì / de)工作。如果你确實需要(yào / yāo)使用AlphaImageLoader,請使用下劃線_filter又使之(zhī)對IE7以(yǐ)上(shàng)版本的(de)用戶無效。


3、把腳本置于(yú)頁面底部      

腳本帶來(lái)的(de)問題就(jiù)是(shì)它阻止了(le/liǎo)頁面的(de)平行下載。HTTP/1.1 規範建議,浏覽器每個(gè)主機名的(de)并行下載内容不(bù)超過兩個(gè)。如果你的(de)圖片放在(zài)多個(gè)主機名上(shàng),你可以(yǐ)在(zài)每個(gè)并行下載中同時(shí)下載2個(gè)以(yǐ)上(shàng)的(de)文件。但是(shì)當下載腳本時(shí),浏覽器就(jiù)不(bù)會同時(shí)下載其它文件了(le/liǎo),即便是(shì)主機名不(bù)相同。      

在(zài)某些情況下把腳本移到(dào)頁面底部可能不(bù)太容易。比如說(shuō),如果腳本中使用了(le/liǎo)document.write來(lái)插入頁面内容,它就(jiù)不(bù)能被往下移動了(le/liǎo)。這(zhè)裏可能還會有作用域的(de)問題。很多情況下,都會遇到(dào)這(zhè)方面的(de)問題。      

一(yī / yì /yí)個(gè)經常用到(dào)的(de)替代方法就(jiù)是(shì)使用延遲腳本。DEFER屬性表明腳本中沒有包含document.write,它告訴浏覽器繼續顯示。不(bù)幸的(de)是(shì),Firefox并不(bù)支持DEFER屬性。在(zài)Internet Explorer中,腳本可能會被延遲但效果也(yě)不(bù)會像我們所期望的(de)那樣。如果腳本可以(yǐ)被延遲,那麽它就(jiù)可以(yǐ)移到(dào)頁面的(de)底部。這(zhè)會讓你的(de)頁面加載的(de)快一(yī / yì /yí)點。


4、剔除重複腳本      

在(zài)同一(yī / yì /yí)個(gè)頁面中重複引用JavaScript文件會影響頁面的(de)性能。你可能會認爲(wéi / wèi)這(zhè)種情況并不(bù)多見。對于(yú)美國(guó)前10大(dà)網站的(de)調查顯示其中有兩家存在(zài)重複引用腳本的(de)情況。有兩種主要(yào / yāo)因素導緻一(yī / yì /yí)個(gè)腳本被重複引用的(de)奇怪現象發生:團隊規模和(hé / huò)腳本數量。如果真的(de)存在(zài)這(zhè)種情況,重複腳本會引起不(bù)必要(yào / yāo)的(de)HTTP請求和(hé / huò)無用的(de)JavaScript運算,這(zhè)降低了(le/liǎo)網站性能。      

在(zài)Internet Explorer中會産生不(bù)必要(yào / yāo)的(de)HTTP請求,而(ér)在(zài)Firefox卻不(bù)會。在(zài)Internet Explorer中,如果一(yī / yì /yí)個(gè)腳本被引用兩次而(ér)且它又不(bù)可緩存,它就(jiù)會在(zài)頁面加載過程中産生兩次HTTP請求。即時(shí)腳本可以(yǐ)緩存,當用戶重載頁面時(shí)也(yě)會産生額外的(de)HTTP請求。      

除增加額外的(de)HTTP請求外,多次運算腳本也(yě)會浪費時(shí)間。在(zài)Internet Explorer和(hé / huò)Firefox中不(bù)管腳本是(shì)否可緩存,它們都存在(zài)重複運算JavaScript的(de)問題。      

一(yī / yì /yí)個(gè)避免偶爾發生的(de)兩次引用同一(yī / yì /yí)腳本的(de)方法是(shì)在(zài)模闆中使用腳本管理模塊引用腳本。在(zài)HTML頁面中使用

标簽引用腳本的(de)最常見方法就(jiù)是(shì):      

<script type="text/javascript" src="menu_1.0.17.js">

在(zài)PHP中可以(yǐ)通過創建名爲(wéi / wèi)insertScript的(de)方法來(lái)替代:      

爲(wéi / wèi)了(le/liǎo)防止多次重複引用腳本,這(zhè)個(gè)方法中還應該使用其它機制來(lái)處理腳本,如檢查所屬目錄和(hé / huò)爲(wéi / wèi)腳本文件名中增加版本号以(yǐ)用于(yú)Expire文件頭等。


5、減少DOM訪問      

使用JavaScript訪問DOM元素比較慢,因此爲(wéi / wèi)了(le/liǎo)獲得更多的(de)應該頁面,應該做到(dào):緩存已經訪問過的(de)有關元素 線下更新完節點之(zhī)後再将它們添加到(dào)文檔樹中 避免使用JavaScript來(lái)修改頁面布局      

有關此方面的(de)更多信息請查看Julien Lecomte在(zài)YUI專題中的(de)文章“高性能Ajax應該程序”。


6、開發智能事件處理程序      

有時(shí)候我們會感覺到(dào)頁面反應遲鈍,這(zhè)是(shì)因爲(wéi / wèi)DOM樹元素中附加了(le/liǎo)過多的(de)事件句柄并且些事件句病被頻繁地(dì / de)觸發。這(zhè)就(jiù)是(shì)爲(wéi / wèi)什麽說(shuō)使用event delegation(事件代理)是(shì)一(yī / yì /yí)種好方法了(le/liǎo)。如果你在(zài)一(yī / yì /yí)個(gè)div中有10個(gè)按鈕,你隻需要(yào / yāo)在(zài)div上(shàng)附加一(yī / yì /yí)次事件句柄就(jiù)可以(yǐ)了(le/liǎo),而(ér)不(bù)用去爲(wéi / wèi)每一(yī / yì /yí)個(gè)按鈕增加一(yī / yì /yí)個(gè)句柄。事件冒泡時(shí)你可以(yǐ)捕捉到(dào)事件并判斷出(chū)是(shì)哪個(gè)事件發出(chū)的(de)。      

你同樣也(yě)不(bù)用爲(wéi / wèi)了(le/liǎo)操作DOM樹而(ér)等待onload事件的(de)發生。你需要(yào / yāo)做的(de)就(jiù)是(shì)等待樹結構中你要(yào / yāo)訪問的(de)元素出(chū)現。你也(yě)不(bù)用等待所有圖像都加載完畢。      

你可能會希望用DOMContentLoaded事件來(lái)代替onload,但是(shì)在(zài)所有浏覽器都支持它之(zhī)前你可使用YUI 事件應用程序中的(de)onAvailable方法。


7、減小Cookie體積      

HTTP coockie可以(yǐ)用于(yú)權限驗證和(hé / huò)個(gè)性化身份等多種用途。coockie内的(de)有關信息是(shì)通過HTTP文件頭來(lái)在(zài)web服務器和(hé / huò)浏覽器之(zhī)間進行交流的(de)。因此保持coockie盡可能的(de)小以(yǐ)減少用戶的(de)響應時(shí)間十分重要(yào / yāo)。 有關更多信息可以(yǐ)查看Tenni Theurer和(hé / huò)Patty Chi的(de)文章“When the Cookie Crumbles”。這(zhè)們研究中主要(yào / yāo)包括:去除不(bù)必要(yào / yāo)的(de)coockie 使coockie體積盡量小以(yǐ)減少對用戶響應的(de)影響 注意在(zài)适應級别的(de)域名上(shàng)設置coockie以(yǐ)便使子(zǐ)域名不(bù)受影響 設置合理的(de)過期時(shí)間。較早地(dì / de)Expire時(shí)間和(hé / huò)不(bù)要(yào / yāo)過早去清除coockie,都會改善用戶的(de)響應時(shí)間。


8、對于(yú)頁面内容使用無coockie域名      

當浏覽器在(zài)請求中同時(shí)請求一(yī / yì /yí)張靜态的(de)圖片和(hé / huò)發送coockie時(shí),服務器對于(yú)這(zhè)些coockie不(bù)會做任何地(dì / de)使用。因此他(tā)們隻是(shì)因爲(wéi / wèi)某些負面因素而(ér)創建的(de)網絡傳輸。所有你應該确定對于(yú)靜态内容的(de)請求是(shì)無coockie的(de)請求。創建一(yī / yì /yí)個(gè)子(zǐ)域名并用他(tā)來(lái)存放所有靜态内容。      

如果你的(de)域名是(shì)www.example.org,你可以(yǐ)在(zài)static.example.org上(shàng)存在(zài)靜态内容。但是(shì),如果你不(bù)是(shì)在(zài)www.example.org上(shàng)而(ér)是(shì)在(zài)頂級域名example.org設置了(le/liǎo)coockie,那麽所有對于(yú)static.example.org的(de)請求都包含coockie。在(zài)這(zhè)種情況下,你可以(yǐ)再重新購買一(yī / yì /yí)個(gè)新的(de)域名來(lái)存在(zài)靜态内容,并且要(yào / yāo)保持這(zhè)個(gè)域名是(shì)無coockie的(de)。Yahoo!使用的(de)是(shì)ymig.com,YouTube使用的(de)是(shì)ytimg.com,Amazon使用的(de)是(shì)images-anazon.com等等。      

使用無coockie域名存在(zài)靜态内容的(de)另外一(yī / yì /yí)個(gè)好處就(jiù)是(shì)一(yī / yì /yí)些代理(服務器)可能會拒絕對coockie的(de)内容請求進行緩存。一(yī / yì /yí)個(gè)相關的(de)建議就(jiù)是(shì),如果你想确定應該使用example.org還是(shì)www.example.org作爲(wéi / wèi)你的(de)一(yī / yì /yí)主頁,你要(yào / yāo)考慮到(dào)coockie帶來(lái)的(de)影響。忽略掉www會使你除了(le/liǎo)把coockie設置到(dào)*.example.org(*是(shì)泛域名解析,代表了(le/liǎo)所有子(zǐ)域名譯者dudo注)外沒有其它選擇,因此出(chū)于(yú)性能方面的(de)考慮最好是(shì)使用帶有www的(de)子(zǐ)域名并且在(zài)它上(shàng)面設置coockie。


9、優化圖像      

設計人(rén)員完成對頁面的(de)設計之(zhī)後,不(bù)要(yào / yāo)急于(yú)将它們上(shàng)傳到(dào)web服務器,這(zhè)裏還需要(yào / yāo)做幾件事:你可以(yǐ)檢查一(yī / yì /yí)下你的(de)GIF圖片中圖像顔色的(de)數量是(shì)否和(hé / huò)調色闆規格一(yī / yì /yí)緻。 使用imagemagick中下面的(de)命令行很容易檢查: identify -verbose image.gif 如果你發現圖片中隻用到(dào)了(le/liǎo)4種顔色,而(ér)在(zài)調色闆的(de)中顯示的(de)256色的(de)顔色槽,那麽這(zhè)張圖片就(jiù)還有壓縮的(de)空間。

嘗試把GIF格式轉換成PNG格式,看看是(shì)否節省空間。大(dà)多數情況下是(shì)可以(yǐ)壓縮的(de)。由于(yú)浏覽器支持有限,設計者們往往不(bù)太樂意使用PNG格式的(de)圖片,不(bù)過這(zhè)都是(shì)過去的(de)事情了(le/liǎo)。現在(zài)隻有一(yī / yì /yí)個(gè)問題就(jiù)是(shì)在(zài)真彩PNG格式中的(de)alpha通道(dào)半透明問題,不(bù)過同樣的(de),GIF也(yě)不(bù)是(shì)真彩格式也(yě)不(bù)支持半透明。因此GIF能做到(dào)的(de),PNG(PNG8)同樣也(yě)能做到(dào)(除了(le/liǎo)動畫)。下面這(zhè)條簡單的(de)命令可以(yǐ)安全地(dì / de)把GIF格式轉換爲(wéi / wèi)PNG格式: convert image.gif image.png “我們要(yào / yāo)說(shuō)的(de)是(shì):給PNG一(yī / yì /yí)個(gè)施展身手的(de)機會吧!” 在(zài)所有的(de)PNG圖片上(shàng)運行pngcrush(或者其它PNG優化工具)。例如: pngcrush image.png -rem alla -reduce -brute result.png 在(zài)所有的(de)JPEG圖片上(shàng)運行jpegtran。這(zhè)個(gè)工具可以(yǐ)對圖片中的(de)出(chū)現的(de)鋸齒等做無損操作,同時(shí)它還可以(yǐ)用于(yú)優化和(hé / huò)清除圖片中的(de)注釋以(yǐ)及其它無用信息(如EXIF信息): jpegtran -copy none -optimize -perfect src.jpg dest.jpg


10、優化CSS不(bù)要(yào / yāo)出(chū)現404錯誤  

Spirite在(zài)Spirite中水平排列你的(de)圖片,垂直排列會稍稍增加文件大(dà)小; Spirite中把顔色較近的(de)組合在(zài)一(yī / yì /yí)起可以(yǐ)降低顔色數,理想狀況是(shì)低于(yú)256色以(yǐ)便适用PNG8格式; 便于(yú)移動,不(bù)要(yào / yāo)在(zài)Spirite的(de)圖像中間留有較大(dà)空隙。這(zhè)雖然不(bù)大(dà)會增加文件大(dà)小但對于(yú)用戶代理來(lái)說(shuō)它需要(yào / yāo)更少的(de)内存來(lái)把圖片解壓爲(wéi / wèi)像素地(dì / de)圖。100x100的(de)圖片爲(wéi / wèi)1萬像素,而(ér)1000x1000就(jiù)是(shì)100萬像素。

HTTP請求時(shí)間消耗是(shì)很大(dà)的(de),因此使用HTTP請求來(lái)獲得一(yī / yì /yí)個(gè)沒有用處的(de)響應(例如404沒有找到(dào)頁面)是(shì)完全沒有必要(yào / yāo)的(de),它隻會降低用戶體驗而(ér)不(bù)會有一(yī / yì /yí)點好處。      

有些站點把404錯誤響應頁面改爲(wéi / wèi)“你是(shì)不(bù)是(shì)要(yào / yāo)找***”,這(zhè)雖然改進了(le/liǎo)用戶體驗但是(shì)同樣也(yě)會浪費服務器資源(如數據庫等)。最糟糕的(de)情況是(shì)指向外部JavaScript的(de)鏈接出(chū)現問題并返回404代碼。首先,這(zhè)種加載會破壞并行加載;其次浏覽器會把試圖在(zài)返回的(de)404響應内容中找到(dào)可能有用的(de)部分當作JavaScript代碼來(lái)執行。


11、使用内容分發網絡      

用戶與你網站服務器的(de)接近程度會影響響應時(shí)間的(de)長短。把你的(de)網站内容分散到(dào)多個(gè)、處于(yú)不(bù)同地(dì / de)域位置的(de)服務器上(shàng)可以(yǐ)加快下載速度。但是(shì)首先我們應該做些什麽呢?      

按地(dì / de)域布置網站内容的(de)第一(yī / yì /yí)步并不(bù)是(shì)要(yào / yāo)嘗試重新架構你的(de)網站讓他(tā)們在(zài)分發服務器上(shàng)正常運行。根據應用的(de)需求來(lái)改變網站結構,這(zhè)可能會包括一(yī / yì /yí)些比較複雜的(de)任務,如在(zài)服務器間同步Session狀态和(hé / huò)合并數據庫更新等。要(yào / yāo)想縮短用戶和(hé / huò)内容服務器的(de)距離,這(zhè)些架構步驟可能是(shì)不(bù)可避免的(de)。      

要(yào / yāo)記住,在(zài)終端用戶的(de)響應時(shí)間中有80%到(dào)90%的(de)響應時(shí)間用于(yú)下載圖像、樣式表、腳本、Flash等頁面内容。這(zhè)就(jiù)是(shì)網站性能黃金守則。和(hé / huò)重新設計你的(de)應用程序架構這(zhè)樣比較困難的(de)任務相比,首先來(lái)分布靜态内容會更好一(yī / yì /yí)點。這(zhè)不(bù)僅會縮短響應時(shí)間,而(ér)且對于(yú)内容分發網絡來(lái)說(shuō)它更容易實現。      

内容分發網絡(Content Delivery Network,CDN)是(shì)由一(yī / yì /yí)系列分散到(dào)各個(gè)不(bù)同地(dì / de)理位置上(shàng)的(de)Web服務器組成的(de),它提高了(le/liǎo)網站内容的(de)傳輸速度。用于(yú)向用戶傳輸内容的(de)服務器主要(yào / yāo)是(shì)根據和(hé / huò)用戶在(zài)網絡上(shàng)的(de)靠近程度來(lái)指定的(de)。例如,擁有最少網絡跳數(network hops)和(hé / huò)響應速度最快的(de)服務器會被選定。      

一(yī / yì /yí)些大(dà)型的(de)網絡公司擁有自己的(de)CDN,但是(shì)使用像Akamai Technologies,Mirror Image Internet, 或者Limelight Networks這(zhè)樣的(de)CDN服務成本卻非常高。對于(yú)剛剛起步的(de)企業和(hé / huò)個(gè)人(rén)網站來(lái)說(shuō),可能沒有使用CDN的(de)成本預算,但是(shì)随着目标用戶群的(de)不(bù)斷擴大(dà)和(hé / huò)更加全球化,CDN就(jiù)是(shì)實現快速響應所必需的(de)了(le/liǎo)。以(yǐ)Yahoo來(lái)說(shuō),他(tā)們轉移到(dào)CDN上(shàng)的(de)網站程序靜态内容節省了(le/liǎo)終端用戶20%以(yǐ)上(shàng)的(de)響應時(shí)間。使用CDN是(shì)一(yī / yì /yí)個(gè)隻需要(yào / yāo)相對簡單地(dì / de)修改代碼實現顯著改善網站訪問速度的(de)方法。


12、爲(wéi / wèi)文件頭指定Expires或Cache-Control      

這(zhè)條守則包括兩方面的(de)内容: 對于(yú)靜态内容:設置文件頭過期時(shí)間Expires的(de)值爲(wéi / wèi)“Never expire”(永不(bù)過期) 對于(yú)動态内容:使用恰當的(de)Cache-Control文件頭來(lái)幫助浏覽器進行有條件的(de)請求      

網頁内容設計現在(zài)越來(lái)越豐富,這(zhè)就(jiù)意味着頁面中要(yào / yāo)包含更多的(de)腳本、樣式表、圖片和(hé / huò)Flash。第一(yī / yì /yí)次訪問你頁面的(de)用戶就(jiù)意味着進行多次的(de)HTTP請求,但是(shì)通過使用Expires文件頭就(jiù)可以(yǐ)使這(zhè)樣内容具有緩存性。它避免了(le/liǎo)接下來(lái)的(de)頁面訪問中不(bù)必要(yào / yāo)的(de)HTTP請求。Expires文件頭經常用于(yú)圖像文件,但是(shì)應該在(zài)所有的(de)内容都使用他(tā),包括腳本、樣式表和(hé / huò)Flash等。      

浏覽器(和(hé / huò)代理)使用緩存來(lái)減少HTTP請求的(de)大(dà)小和(hé / huò)次數以(yǐ)加快頁面訪問速度。Web服務器在(zài)HTTP響應中使用Expires文件頭來(lái)告訴客戶端内容需要(yào / yāo)緩存多長時(shí)間。下面這(zhè)個(gè)例子(zǐ)是(shì)一(yī / yì /yí)個(gè)較長時(shí)間的(de)Expires文件頭,它告訴浏覽器這(zhè)個(gè)響應直到(dào)2010年4月15日才過期。      Expires: Thu, 15 Apr 2010 20:00:00 GMT      如果你使用的(de)是(shì)Apache服務器,可以(yǐ)使用ExpiresDefault來(lái)設定相對當前日期的(de)過期時(shí)間。下面這(zhè)個(gè)例子(zǐ)是(shì)使用ExpiresDefault來(lái)設定請求時(shí)間後10年過期的(de)文件頭:      

ExpiresDefault "access plus 10 years"      

要(yào / yāo)切記,如果使用了(le/liǎo)Expires文件頭,當頁面内容改變時(shí)就(jiù)必須改變内容的(de)文件名。依Yahoo!來(lái)說(shuō)我們經常使用這(zhè)樣的(de)步驟:在(zài)内容的(de)文件名中加上(shàng)版本号,如yahoo_2.0.6.js。      

使用Expires文件頭隻有會在(zài)用戶已經訪問過你的(de)網站後才會起作用。當用戶首次訪問你的(de)網站時(shí)這(zhè)對減少HTTP請求次數來(lái)說(shuō)是(shì)無效的(de),因爲(wéi / wèi)浏覽器的(de)緩存是(shì)空的(de)。因此這(zhè)種方法對于(yú)你網站性能的(de)改進情況要(yào / yāo)依據他(tā)們“預緩存”存在(zài)時(shí)對你頁面的(de)點擊頻率(“預緩存”中已經包含了(le/liǎo)頁面中的(de)所有内容)。Yahoo!建立了(le/liǎo)一(yī / yì /yí)套測量方法,我們發現所有的(de)頁面浏覽量中有75~85%都有“預緩存”。通過使用Expires文件頭,增加了(le/liǎo)緩存在(zài)浏覽器中内容的(de)數量,并且可以(yǐ)在(zài)用戶接下來(lái)的(de)請求中再次使用這(zhè)些内容,這(zhè)甚至都不(bù)需要(yào / yāo)通過用戶發送一(yī / yì /yí)個(gè)字節的(de)請求。


13、Gzip壓縮文件内容      

網絡傳輸中的(de)HTTP請求和(hé / huò)應答時(shí)間可以(yǐ)通過前端機制得到(dào)顯著改善。的(de)确,終端用戶的(de)帶寬、互聯網提供者、與對等交換點的(de)靠近程度等都不(bù)是(shì)網站開發者所能決定的(de)。但是(shì)還有其他(tā)因素影響着響應時(shí)間。通過減小HTTP響應的(de)大(dà)小可以(yǐ)節省HTTP響應時(shí)間。      

從HTTP/1.1開始,web客戶端都默認支持HTTP請求中有Accept-Encoding文件頭的(de)壓縮格式:Accept-Encoding: gzip, deflate      

如果web服務器在(zài)請求的(de)文件頭中檢測到(dào)上(shàng)面的(de)代碼,就(jiù)會以(yǐ)客戶端列出(chū)的(de)方式壓縮響應内容。Web服務器把壓縮方式通過響應文件頭中的(de)Content-Encoding來(lái)返回給浏覽器。    

Content-Encoding: gzip

Gzip是(shì)目前最流行也(yě)是(shì)最有效的(de)壓縮方式。這(zhè)是(shì)由GNU項目開發并通過RFC 1952來(lái)标準化的(de)。另外僅有的(de)一(yī / yì /yí)個(gè)壓縮格式是(shì)deflate,但是(shì)它的(de)使用範圍有限效果也(yě)稍稍遜色。

Gzip大(dà)概可以(yǐ)減少70%的(de)響應規模。目前大(dà)約有90%通過浏覽器傳輸的(de)互聯網交換支持gzip格式。如果你使用的(de)是(shì)Apache,gzip模塊配置和(hé / huò)你的(de)版本有關:Apache 1.3使用mod_zip,而(ér)Apache 2.x使用moflate。      

浏覽器和(hé / huò)代理都會存在(zài)這(zhè)樣的(de)問題:浏覽器期望收到(dào)的(de)和(hé / huò)實際接收到(dào)的(de)内容會存在(zài)不(bù)匹配的(de)現象。幸好,這(zhè)種特殊情況随着舊式浏覽器使用量的(de)減少在(zài)減少。Apache模塊會通過自動添加适當的(de)Vary響應文件頭來(lái)避免這(zhè)種狀況的(de)出(chū)現。      

服務器根據文件類型來(lái)選擇需要(yào / yāo)進行gzip壓縮的(de)文件,但是(shì)這(zhè)過于(yú)限制了(le/liǎo)可壓縮的(de)文件。大(dà)多數web服務器會壓縮HTML文檔。對腳本和(hé / huò)樣式表進行壓縮同樣也(yě)是(shì)值得做的(de)事情,但是(shì)很多web服務器都沒有這(zhè)個(gè)功能。實際上(shàng),壓縮任何一(yī / yì /yí)個(gè)文本類型的(de)響應,包括XML和(hé / huò)JSON,都值得的(de)。圖像和(hé / huò)PDF文件由于(yú)已經壓縮過了(le/liǎo)所以(yǐ)不(bù)能再進行gzip壓縮。如果試圖gizp壓縮這(zhè)些文件的(de)話不(bù)但會浪費CPU資源還會增加文件的(de)大(dà)小。      

Gzip壓縮所有可能的(de)文件類型是(shì)減少文件體積增加用戶體驗的(de)簡單方法。


14、配置ETag      

Entity tags(ETags)(實體标簽)是(shì)web服務器和(hé / huò)浏覽器用于(yú)判斷浏覽器緩存中的(de)内容和(hé / huò)服務器中的(de)原始内容是(shì)否匹配的(de)一(yī / yì /yí)種機制(“實體”就(jiù)是(shì)所說(shuō)的(de)“内容”,包括圖片、腳本、樣式表等)。增加ETag爲(wéi / wèi)實體的(de)驗證提供了(le/liǎo)一(yī / yì /yí)個(gè)比使用“last-modified date(上(shàng)次編輯時(shí)間)”更加靈活的(de)機制。Etag是(shì)一(yī / yì /yí)個(gè)識别内容版本号的(de)唯一(yī / yì /yí)字符串。唯一(yī / yì /yí)的(de)格式限制就(jiù)是(shì)它必須包含在(zài)雙引号内。原始服務器通過含有ETag文件頭的(de)響應指定頁面内容的(de)ETag。

HTTP/1.1 200 OK      Last-Modified: Tue, 12 Dec 2006 03:03:59 GMT   ETag: "10c24bc-4ab-457e1c1f"      Content-Length: 12195      

稍後,如果浏覽器要(yào / yāo)驗證一(yī / yì /yí)個(gè)文件,它會使用If-None-Match文件頭來(lái)把ETag傳回給原始服務器。在(zài)這(zhè)個(gè)例子(zǐ)中,如果ETag匹配,就(jiù)會返回一(yī / yì /yí)個(gè)304狀态碼,這(zhè)就(jiù)節省了(le/liǎo)12195字節的(de)響應。      GET /i/yahoo.gif HTTP/1.1      Host: us.yimg.com      If-Modified-Since: Tue, 12 Dec 2006 03:03:59 GMT      If-None-Match: "10c24bc-4ab-457e1c1f"      HTTP/1.1 304 Not Modified      

ETag的(de)問題在(zài)于(yú),它是(shì)根據可以(yǐ)辨别網站所在(zài)的(de)服務器的(de)具有唯一(yī / yì /yí)性的(de)屬性來(lái)生成的(de)。當浏覽器從一(yī / yì /yí)台服務器上(shàng)獲得頁面内容後到(dào)另外一(yī / yì /yí)台服務器上(shàng)進行驗證時(shí)ETag就(jiù)會不(bù)匹配,這(zhè)種情況對于(yú)使用服務器組和(hé / huò)處理請求的(de)網站來(lái)說(shuō)是(shì)非常常見的(de)。默認情況下,Apache和(hé / huò)IIS都會把數據嵌入ETag中,這(zhè)會顯著減少多服務器間的(de)文件驗證沖突。      

Apache 1.3和(hé / huò)2.x中的(de)ETag格式爲(wéi / wèi)inode-size-timestamp。即使某個(gè)文件在(zài)不(bù)同的(de)服務器上(shàng)會處于(yú)相同的(de)目錄下,文件大(dà)小、權限、時(shí)間戳等都完全相同,但是(shì)在(zài)不(bù)同服務器上(shàng)他(tā)們的(de)内碼也(yě)是(shì)不(bù)同的(de)。      

IIS 5.0和(hé / huò)IIS 6.0處理ETag的(de)機制相似。IIS中的(de)ETag格式爲(wéi / wèi)Filetimestamp:ChangeNumber。用ChangeNumber來(lái)跟蹤IIS配置的(de)改變。網站所用的(de)不(bù)同IIS服務器間ChangeNumber也(yě)不(bù)相同。 不(bù)同的(de)服務器上(shàng)的(de)Apache和(hé / huò)IIS即使對于(yú)完全相同的(de)内容産生的(de)ETag在(zài)也(yě)不(bù)相同,用戶并不(bù)會接收到(dào)一(yī / yì /yí)個(gè)小而(ér)快的(de)304響應;相反他(tā)們會接收一(yī / yì /yí)個(gè)正常的(de)200響應并下載全部内容。如果你的(de)網站隻放在(zài)一(yī / yì /yí)台服務器上(shàng),就(jiù)不(bù)會存在(zài)這(zhè)個(gè)問題。但是(shì)如果你的(de)網站是(shì)架設在(zài)多個(gè)服務器上(shàng),并且使用Apache和(hé / huò)IIS産生默認的(de)ETag配置,你的(de)用戶獲得頁面就(jiù)會相對慢一(yī / yì /yí)點,服務器會傳輸更多的(de)内容,占用更多的(de)帶寬,代理也(yě)不(bù)會有效地(dì / de)緩存你的(de)網站内容。即使你的(de)内容擁有Expires文件頭,無論用戶什麽時(shí)候點擊“刷新”或者“重載”按鈕都會發送相應的(de)GET請求。      

如果你沒有使用ETag提供的(de)靈活的(de)驗證模式,那麽幹脆把所有的(de)ETag都去掉會更好。Last-Modified文件頭驗證是(shì)基于(yú)内容的(de)時(shí)間戳的(de)。去掉ETag文件頭會減少響應和(hé / huò)下次請求中文件的(de)大(dà)小。微軟的(de)這(zhè)篇支持文稿講述了(le/liǎo)如何去掉ETag。在(zài)Apache中,隻需要(yào / yāo)在(zài)配置文件中簡單添加下面一(yī / yì /yí)行代碼就(jiù)可以(yǐ)了(le/liǎo):FileETag none


15、盡早刷新輸出(chū)緩沖      

當用戶請求一(yī / yì /yí)個(gè)頁面時(shí),無論如何都會花費200到(dào)500毫秒用于(yú)後台組織HTML文件。在(zài)這(zhè)期間,浏覽器會一(yī / yì /yí)直空閑等待數據返回。在(zài)PHP中,你可以(yǐ)使用flush()方法,它允許你把已經編譯的(de)好的(de)部分HTML響應文件先發送給浏覽器,這(zhè)時(shí)浏覽器就(jiù)會可以(yǐ)下載文件中的(de)内容(腳本等)而(ér)後台同時(shí)處理剩餘的(de)HTML頁面。這(zhè)樣做的(de)效果會在(zài)後台煩惱或者前台較空閑時(shí)更加明顯。      

輸出(chū)緩沖應用最好的(de)一(yī / yì /yí)個(gè)地(dì / de)方就(jiù)是(shì)緊跟在(zài)之(zhī)後,因爲(wéi / wèi)HTML的(de)頭部分容易生成而(ér)且頭部往往包含CSS和(hé / huò)JavaScript文件,這(zhè)樣浏覽器就(jiù)可以(yǐ)在(zài)後台編譯剩餘HTML的(de)同時(shí)并行下載它們。

爲(wéi / wèi)了(le/liǎo)證明使用這(zhè)項技術的(de)好處,Yahoo!搜索率先研究并完成了(le/liǎo)用戶測試。


16、使用GET來(lái)完成AJAX請求      

Yahoo!Mail團隊發現,當使用XMLHttpRequest時(shí),浏覽器中的(de)POST方法是(shì)一(yī / yì /yí)個(gè)“兩步走”的(de)過程:首先發送文件頭,然後才發送數據。因此使用GET最爲(wéi / wèi)恰當,因爲(wéi / wèi)它隻需發送一(yī / yì /yí)個(gè)TCP包(除非你有很多cookie)。IE中URL的(de)最大(dà)長度爲(wéi / wèi)2K,因此如果你要(yào / yāo)發送一(yī / yì /yí)個(gè)超過2K的(de)數據時(shí)就(jiù)不(bù)能使用GET了(le/liǎo)。      

一(yī / yì /yí)個(gè)有趣的(de)不(bù)同就(jiù)是(shì)POST并不(bù)像GET那樣實際發送數據。根據HTTP規範,GET意味着“獲取”數據,因此當你僅僅獲取數據時(shí)使用GET更加有意義(從語意上(shàng)講也(yě)是(shì)如此),相反,發送并在(zài)服務端保存數據時(shí)使用POST。


17、把樣式表置于(yú)頂部      

在(zài)研究Yahoo!的(de)性能表現時(shí),我們發現把樣式表放到(dào)文檔的(de)内部似乎會加快頁面的(de)下載速度。這(zhè)是(shì)因爲(wéi / wèi)把樣式表放到(dào)内會使頁面有步驟的(de)加載顯示。      

注重性能的(de)前端服務器往往希望頁面有秩序地(dì / de)加載。同時(shí),我們也(yě)希望浏覽器把已經接收到(dào)内容盡可能顯示出(chū)來(lái)。這(zhè)對于(yú)擁有較多内容的(de)頁面和(hé / huò)網速較慢的(de)用戶來(lái)說(shuō)特别重要(yào / yāo)。向用戶返回可視化的(de)反饋,比如進程指針,已經有了(le/liǎo)較好的(de)研究并形成了(le/liǎo)正式文檔。在(zài)我們的(de)研究中HTML頁面就(jiù)是(shì)進程指針。當浏覽器有序地(dì / de)加載文件頭、導航欄、頂部的(de)logo等對于(yú)等待頁面加載的(de)用戶來(lái)說(shuō)都可以(yǐ)作爲(wéi / wèi)可視化的(de)反饋。這(zhè)從整體上(shàng)改善了(le/liǎo)用戶體驗。      

把樣式表放在(zài)文檔底部的(de)問題是(shì)在(zài)包括Internet Explorer在(zài)内的(de)很多浏覽器中這(zhè)會中止内容的(de)有序呈現。浏覽器中止呈現是(shì)爲(wéi / wèi)了(le/liǎo)避免樣式改變引起的(de)頁面元素重繪。用戶不(bù)得不(bù)面對一(yī / yì /yí)個(gè)空白頁面。      

HTML規範清楚指出(chū)樣式表要(yào / yāo)放包含在(zài)頁面的(de)區域内:“和(hé / huò)不(bù)同,隻能出(chū)現在(zài)文檔的(de)區域内,盡管它可以(yǐ)多次使用它”。無論是(shì)引起白屏還是(shì)出(chū)現沒有樣式化的(de)内容都不(bù)值得去嘗試。最好的(de)方案就(jiù)是(shì)按照HTML規範在(zài)文檔内加載你的(de)樣式表。


18、避免使用CSS表達式(Expression)      

CSS表達式是(shì)動态設置CSS屬性的(de)強大(dà)(但危險)方法。Internet Explorer從第5個(gè)版本開始支持CSS表達式。下面的(de)例子(zǐ)中,使用CSS表達式可以(yǐ)實現隔一(yī / yì /yí)個(gè)小時(shí)切換一(yī / yì /yí)次背景顔色:background-color: expression( (new Date()).getHours()%2 ? "#B8D4FF" : "#F08A00" ); 如上(shàng)所示,expression中使用了(le/liǎo)JavaScript表達式。CSS屬性根據JavaScript表達式的(de)計算結果來(lái)設置。expression方法在(zài)其它浏覽器中不(bù)起作用,因此在(zài)跨浏覽器的(de)設計中單獨針對Internet Explorer設置時(shí)會比較有用。      

表達式的(de)問題就(jiù)在(zài)于(yú)它的(de)計算頻率要(yào / yāo)比我們想象的(de)多。不(bù)僅僅是(shì)在(zài)頁面顯示和(hé / huò)縮放時(shí),就(jiù)是(shì)在(zài)頁面滾動、乃至移動鼠标時(shí)都會要(yào / yāo)重新計算一(yī / yì /yí)次。給CSS表達式增加一(yī / yì /yí)個(gè)計數器可以(yǐ)跟蹤表達式的(de)計算頻率。在(zài)頁面中随便移動鼠标都可以(yǐ)輕松達到(dào)10000次以(yǐ)上(shàng)的(de)計算量。      

一(yī / yì /yí)個(gè)減少CSS表達式計算次數的(de)方法就(jiù)是(shì)使用一(yī / yì /yí)次性的(de)表達式,它在(zài)第一(yī / yì /yí)次運行時(shí)将結果賦給指定的(de)樣式屬性,并用這(zhè)個(gè)屬性來(lái)代替CSS表達式。如果樣式屬性必須在(zài)頁面周期内動态地(dì / de)改變,使用事件句柄來(lái)代替CSS表達式是(shì)一(yī / yì /yí)個(gè)可行辦法。如果必須使用CSS表達式,一(yī / yì /yí)定要(yào / yāo)記住它們要(yào / yāo)計算成千上(shàng)萬次并且可能會對你頁面的(de)性能産生影響。


19、使用外部JavaScript和(hé / huò)CSS      

很多性能規則都是(shì)關于(yú)如何處理外部文件的(de)。但是(shì),在(zài)你采取這(zhè)些措施前你可能會問到(dào)一(yī / yì /yí)個(gè)更基本的(de)問題:JavaScript和(hé / huò)CSS是(shì)應該放在(zài)外部文件中呢還是(shì)把它們放在(zài)頁面本身之(zhī)内呢?      

在(zài)實際應用中使用外部文件可以(yǐ)提高頁面速度,因爲(wéi / wèi)JavaScript和(hé / huò)CSS文件都能在(zài)浏覽器中産生緩存。内置在(zài)HTML文檔中的(de)JavaScript和(hé / huò)CSS則會在(zài)每次請求中随HTML文檔重新下載。這(zhè)雖然減少了(le/liǎo)HTTP請求的(de)次數,卻增加了(le/liǎo)HTML文檔的(de)大(dà)小。從另一(yī / yì /yí)方面來(lái)說(shuō),如果外部文件中的(de)JavaScript和(hé / huò)CSS被浏覽器緩存,在(zài)沒有增加HTTP請求次數的(de)同時(shí)可以(yǐ)減少HTML文檔的(de)大(dà)小。      

關鍵問題是(shì),外部JavaScript和(hé / huò)CSS文件緩存的(de)頻率和(hé / huò)請求HTML文檔的(de)次數有關。雖然有一(yī / yì /yí)定的(de)難度,但是(shì)仍然有一(yī / yì /yí)些指标可以(yǐ)一(yī / yì /yí)測量它。如果一(yī / yì /yí)個(gè)會話中用戶會浏覽你網站中的(de)多個(gè)頁面,并且這(zhè)些頁面中會重複使用相同的(de)腳本和(hé / huò)樣式表,緩存外部文件就(jiù)會帶來(lái)更大(dà)的(de)益處。      

許多網站沒有功能建立這(zhè)些指标。對于(yú)這(zhè)些網站來(lái)說(shuō),最好的(de)堅決方法就(jiù)是(shì)把JavaScript和(hé / huò)CSS作爲(wéi / wèi)外部文件引用。比較适合使用内置代碼的(de)例外就(jiù)是(shì)網站的(de)主頁,如Yahoo!主頁和(hé / huò)My Yahoo!。主頁在(zài)一(yī / yì /yí)次會話中擁有較少(可能隻有一(yī / yì /yí)次)的(de)浏覽量,你可以(yǐ)發現内置JavaScript和(hé / huò)CSS對于(yú)終端用戶來(lái)說(shuō)會加快響應時(shí) 間。      

對于(yú)擁有較大(dà)浏覽量的(de)首頁來(lái)說(shuō),有一(yī / yì /yí)種技術可以(yǐ)平衡内置代碼帶來(lái)的(de)HTTP請求減少與通過使用外部文件進行緩存帶來(lái)的(de)好處。其中一(yī / yì /yí)個(gè)就(jiù)是(shì)在(zài)首頁中内置JavaScript和(hé / huò)CSS,但是(shì)在(zài)頁面下載完成後動态下載外部文件,在(zài)子(zǐ)頁面中使用到(dào)這(zhè)些文件時(shí),它們已經緩存到(dào)浏覽器了(le/liǎo)。


20、削減JavaScript和(hé / huò)CSS      

精簡是(shì)指從去除代碼不(bù)必要(yào / yāo)的(de)字符減少文件大(dà)小從而(ér)節省下載時(shí)間。消減代碼時(shí),所有的(de)注釋、不(bù)需要(yào / yāo)的(de)空白字符(空格、換行、tab縮進)等都要(yào / yāo)去掉。在(zài)JavaScript中,由于(yú)需要(yào / yāo)下載的(de)文件體積變小了(le/liǎo)從而(ér)節省了(le/liǎo)響應時(shí)間。精簡JavaScript中目前用到(dào)的(de)最廣泛的(de)兩個(gè)工具是(shì)JSMin和(hé / huò)YUI Compressor。YUI Compressor還可用于(yú)精簡CSS。      

混淆是(shì)另外一(yī / yì /yí)種可用于(yú)源代碼優化的(de)方法。這(zhè)種方法要(yào / yāo)比精簡複雜一(yī / yì /yí)些并且在(zài)混淆的(de)過程更易産生問題。在(zài)對美國(guó)前10大(dà)網站的(de)調查中發現,精簡也(yě)可以(yǐ)縮小原來(lái)代碼體積的(de)21%,而(ér)混淆可以(yǐ)達到(dào)25%。盡管混淆法可以(yǐ)更好地(dì / de)縮減代碼,但是(shì)對于(yú)JavaScript來(lái)說(shuō)精簡的(de)風險更小。      

除消減外部的(de)腳本和(hé / huò)樣式表文件外,