頁面效能優化的34條黃金守則
1、儘量減少HTTP請求次數
2、減少DNS查詢次數
域名系統(DNS)提供了域名和IP的對應關係,就像電話本中人名和他們的電話號碼的關係一樣。當你在瀏覽器位址列中輸入www.rjboy.cn時,DNS解析伺服器就會返回這個域名對應的IP地址。DNS解析的過程同樣也是需要時間的。一般情況下返回給定域名對應的IP地址會花費20到120毫秒的時間。而且在這個過程中瀏覽器什麼都不會做直到DNS查詢完畢。
3、避免跳轉
要記住跳轉會降低使用者體驗。在使用者和HTML文件中間增加一個跳轉,會拖延頁面中所有元素的顯示,因為在HTML檔案被載入前任何檔案(影象、Flash等)都不會被下載。
4、可快取的AJAX
5、推遲載入內容
你可以仔細看一下你的網頁,問問自己“哪些內容是頁面呈現時所必需首先載入的?哪些內容和結構可以稍後再載入?
把整個過程按照onload事件分隔成兩部分,JavaScript是一個理想的選擇。例如,如果你有用於實現拖放和動畫的JavaScript,那麼它就以等待稍後載入,因為頁面上的拖放元素是在初始化呈現之後才發生的。其它的例如隱藏部分的內容(使用者操作之後才顯現的內容)和處於摺疊部分的影象也可以推遲載入。
6、預載入
預載入和後加載看起來似乎恰恰相反,但實際上預載入是為了實現另外一種目標。預載入是在瀏覽器空閒時請求將來可能會用到的頁面內容(如影象、樣式表和指令碼)。使用這種方法,當用戶要訪問下一個頁面時,頁面中的內容大部分已經載入到快取中了,因此可以大大改善訪問速度。
7、減少DOM元素數量
一個複雜的頁面意味著需要下載更多資料,同時也意味著JavaScript遍歷DOM的效率越慢。比如當你增加一個事件控制代碼時在500和5000個DOM元素中迴圈效果肯定是不一樣的。
8、根據域名劃分頁面內容
把頁面內容劃分成若干部分可以使你最大限度地實現平行下載。由於DNS查詢帶來的影響你首先要確保你使用的域名數量在2個到4個之間。例如,你可以把用到的HTML內容和動態內容放在www.example.org上,而把頁面各種元件(圖片、指令碼、CSS)分別存放在statics1.example.org和statics.example.org上。
9、使iframe的數量最小
<iframe>
<iframe>
的缺點:即時內容為空,載入也需要時間;會阻止頁面載入 ;沒有語意 。
10、不要出現404錯誤
11、使用內容分發網路
使用者與你網站伺服器的接近程度會影響響應時間的長短。把你的網站內容分散到多個、處於不同地域位置的伺服器上可以加快下載速度。
12、為檔案頭指定Expires或Cache-Control
這條守則包括兩方面的內容:
對於靜態內容:設定檔案頭過期時間Expires的值為“Never expire”(永不過期)
對於動態內容:使用恰當的Cache-Control檔案頭來幫助瀏覽器進行有條件的請求
13、Gzip壓縮檔案內容
Gzip壓縮所有可能的檔案型別是減少檔案體積增加使用者體驗的簡單方法。
14、配置ETag
Entity tags(ETags)(實體標籤)是web伺服器和瀏覽器用於判斷瀏覽器快取中的內容和伺服器中的原始內容是否匹配的一種機制(“實體”就是所說的“內容”,包括圖片、指令碼、樣式表等)。增加ETag為實體的驗證提供了一個比使用“last-modified date(上次編輯時間)”更加靈活的機制。Etag是一個識別內容版本號的唯一字串。唯一的格式限制就是它必須包含在雙引號內。原始伺服器通過含有ETag檔案頭的響應指定頁面內容的ETag。
15、儘早重新整理輸出緩衝
當用戶請求一個頁面時,無論如何都會花費200到500毫秒用於後臺組織HTML檔案。在這期間,瀏覽器會一直空閒等待資料返回。在PHP中,你可以使用flush()方法,它允許你把已經編譯的好的部分HTML響應檔案先發送給瀏覽器,這時瀏覽器就會可以下載檔案中的內容(指令碼等)而後臺同時處理剩餘的HTML頁面。這樣做的效果會在後臺煩惱或者前臺較空閒時更加明顯。
輸出緩衝應用最好的一個地方就是緊跟在<head/>
之後,因為HTML的頭部分容易生成而且頭部往往包含CSS和JavaScript檔案,這樣瀏覽器就可以在後臺編譯剩餘HTML的同時並行下載它們。
16、使用GET來完成AJAX請求
Yahoo!Mail團隊發現,當使用XMLHttpRequest時,瀏覽器中的POST方法是一個“兩步走”的過程:首先發送檔案頭,然後才傳送資料。因此使用GET最為恰當,因為它只需傳送一個TCP包(除非你有很多cookie)。IE中URL的最大長度為2K,因此如果你要傳送一個超過2K的資料時就不能使用GET了。
一個有趣的不同就是POST並不像GET那樣實際傳送資料。根據HTTP規範,GET意味著“獲取”資料,因此當你僅僅獲取資料時使用GET更加有意義(從語意上講也是如此),相反,傳送並在服務端儲存資料時使用POST。
17、把樣式表置於頂部
在研究Yahoo!的效能表現時,我們發現把樣式表放到文件的<head />
內部似乎會加快頁面的下載速度。這是因為把樣式表放到<head />
內會使頁面有步驟的載入顯示。
18、避免使用CSS表示式(Expression)
19、使用外部JavaScript和CSS
很多效能規則都是關於如何處理外部檔案的。但是,在你採取這些措施前你可能會問到一個更基本的問題:JavaScript和CSS是應該放在外部檔案中呢還是把它們放在頁面本身之內呢?
在實際應用中使用外部檔案可以提高頁面速度,因為JavaScript和CSS檔案都能在瀏覽器中產生快取。內建在HTML文件中的JavaScript和CSS則會在每次請求中隨HTML文件重新下載。這雖然減少了HTTP請求的次數,卻增加了HTML文件的大小。從另一方面來說,如果外部檔案中的JavaScript和CSS被瀏覽器快取,在沒有增加HTTP請求次數的同時可以減少HTML文件的大小。
關鍵問題是,外部JavaScript和CSS檔案快取的頻率和請求HTML文件的次數有關。雖然有一定的難度,但是仍然有一些指標可以一測量它。如果一個會話中使用者會瀏覽你網站中的多個頁面,並且這些頁面中會重複使用相同的指令碼和樣式表,快取外部檔案就會帶來更大的益處。
許多網站沒有功能建立這些指標。對於這些網站來說,最好的堅決方法就是把JavaScript和CSS作為外部檔案引用。比較適合使用內建程式碼的例外就是網站的主頁,如Yahoo!主頁和My Yahoo!。主頁在一次會話中擁有較少(可能只有一次)的瀏覽量,你可以發現內建JavaScript和CSS對於終端使用者來說會加快響應時間。
對於擁有較大瀏覽量的首頁來說,有一種技術可以平衡內建程式碼帶來的HTTP請求減少與通過使用外部檔案進行快取帶來的好處。其中一個就是在首頁中內建JavaScript和CSS,但是在頁面下載完成後動態下載外部檔案,在子頁面中使用到這些檔案時,它們已經快取到瀏覽器了。
20、削減JavaScript和CSS
21、用<link>
代替@import
前面的最佳實現中提到CSS應該放置在頂端以利於有序載入呈現。
在IE中,頁面底部@import
和使用<link>
作用是一樣的,因此最好不要使用它。
22、避免使用濾鏡
IE獨有屬性AlphaImageLoader用於修正7.0以下版本中顯示PNG圖片的半透明效果。這個濾鏡的問題在於瀏覽器載入圖片時它會終止內容的呈現並且凍結瀏覽器。在每一個元素(不僅僅是圖片)它都會運算一次,增加了記憶體開支,因此它的問題是多方面的。
完全避免使用AlphaImageLoader的最好方法就是使用PNG8格式來代替,這種格式能在IE中很好地工作。如果你確實需要使用AlphaImageLoader,請使用下劃線_filter又使之對IE7以上版本的使用者無效。
23、把指令碼置於頁面底部
指令碼帶來的問題就是它阻止了頁面的平行下載。HTTP/1.1 規範建議,瀏覽器每個主機名的並行下載內容不超過兩個。如果你的圖片放在多個主機名上,你可以在每個並行下載中同時下載2個以上的檔案。但是當下載指令碼時,瀏覽器就不會同時下載其它檔案了,即便是主機名不相同。
在某些情況下把指令碼移到頁面底部可能不太容易。比如說,如果指令碼中使用了document.write來插入頁面內容,它就不能被往下移動了。這裡可能還會有作用域的問題。很多情況下,都會遇到這方面的問題。
一個經常用到的替代方法就是使用延遲指令碼。DEFER屬性表明指令碼中沒有包含document.write,它告訴瀏覽器繼續顯示。不幸的是,Firefox並不支援DEFER屬性。在Internet Explorer中,指令碼可能會被延遲但效果也不會像我們所期望的那樣。如果指令碼可以被延遲,那麼它就可以移到頁面的底部。這會讓你的頁面載入的快一點。
24、剔除重複指令碼
25、減少DOM訪問
使用JavaScript訪問DOM元素比較慢,因此為了獲得更多的應該頁面,應該做到:
快取已經訪問過的有關元素
線下更新完節點之後再將它們新增到文件樹中
避免使用JavaScript來修改頁面佈局
有關此方面的更多資訊請檢視Julien Lecomte在YUI專題中的文章“高效能Ajax應該程式”。
26、開發智慧事件處理程式
有時候我們會感覺到頁面反應遲鈍,這是因為DOM樹元素中附加了過多的事件控制代碼並且些事件句病被頻繁地觸發。這就是為什麼說使用event delegation(事件代理)是一種好方法了。如果你在一個div中有10個按鈕,你只需要在div上附加一次事件控制代碼就可以了,而不用去為每一個按鈕增加一個控制代碼。事件冒泡時你可以捕捉到事件並判斷出是哪個事件發出的。
你同樣也不用為了操作DOM樹而等待onload事件的發生。你需要做的就是等待樹結構中你要訪問的元素出現。你也不用等待所有影象都載入完畢。
你可能會希望用DOMContentLoaded事件來代替onload,但是在所有瀏覽器都支援它之前你可使用YUI 事件應用程式中的onAvailable方法。
27、減小Cookie體積
28、對於頁面內容使用無coockie域名
當瀏覽器在請求中同時請求一張靜態的圖片和傳送coockie時,伺服器對於這些coockie不會做任何地使用。因此他們只是因為某些負面因素而建立的網路傳輸。所有你應該確定對於靜態內容的請求是無coockie的請求。建立一個子域名並用他來存放所有靜態內容。
如果你的域名是www.example.org,你可以在static.example.org上存在靜態內容。但是,如果你不是在www.example.org上而是在頂級域名example.org設定了coockie,那麼所有對於static.example.org的請求都包含coockie。在這種情況下,你可以再重新購買一個新的域名來存在靜態內容,並且要保持這個域名是無coockie的。Yahoo!使用的是ymig.com,YouTube使用的是ytimg.com,Amazon使用的是images-anazon.com等等。
使用無coockie域名存在靜態內容的另外一個好處就是一些代理(伺服器)可能會拒絕對coockie的內容請求進行快取。一個相關的建議就是,如果你想確定應該使用example.org還是www.example.org作為你的一主頁,你要考慮到coockie帶來的影響。忽略掉www會使你除了把coockie設定到.example.org(是泛域名解析,代表了所有子域名譯者dudo注)外沒有其它選擇,因此出於效能方面的考慮最好是使用帶有www的子域名並且在它上面設定coockie。
29、優化影象
30、優化CSS Spirite
在Spirite中水平排列你的圖片,垂直排列會稍稍增加檔案大小;
Spirite中把顏色較近的組合在一起可以降低顏色數,理想狀況是低於256色以便適用PNG8格式;
便於移動,不要在Spirite的影象中間留有較大空隙。這雖然不大會增加檔案大小但對於使用者代理來說它需要更少的記憶體來把圖片解壓為畫素地圖。100×100的圖片為1萬畫素,而1000×1000就是100萬畫素。
31、不要在HTML中縮放影象
不要為了在HTML中設定長寬而使用比實際需要大的圖片。如果你需要: