1、減少HTTP請求
why
減少響應時間。
how
- CSS Sprites
- 合併樣式腳本
- 內聯圖片(使用data:URL模式可以在web頁面中包含圖片但不需要額外的HTTP請求)
2、使用內容發佈網絡(CDN)
why
瀏覽器是根據域(Domain)來緩存內容資源的,只要域不一樣,那麼它就需要重複下載這些資源,而且使用同樣的方式將它們緩存起來。
帶來的問題:重複地下載,這會佔用網絡資源和緩存空間。
how
如果有很多站點,它們之間可以共享某些內容(例如javascript,css,image等),那麼與其每個站點放一份,就不如將他們統一地存在在一個地方,這樣就可以減少下載的次數和緩存的體積了。
如:引用jquery cdn
<script src="https://code.jquery.com/jquery-2.2.4.js"></script>
3、添加Expires頭
why
使內容具有緩存性
how
Expires: Thu, 01 Dec 1994 16:00:00 GMT (必須是GMT格式)
通過HTTP的META設置expires和cache-control
<meta http-equiv="Cache-Control" content="max-age=7200" />
<meta http-equiv="Expires" content="Mon, 20 Jul 2009 23:00:00 GMT" />
上述設置僅為舉例,實際使用其一即可。這樣寫的話僅對該網頁有效,對網頁中的圖片或其他請求無效,並不會做任何cache。
4、壓縮組件
why
減小文件體積,提升頁面加載速度
how
壓縮腳本和樣式表
5、樣式置頂
why
放在底部可能會出現白屏,會阻塞頁面的逐步呈現
注意:使用link,不使用@import(可能出現白屏,以及下載組件無序性)
6、腳本置底
why
頁面既可以逐步呈現,也可以提高資源下載的並行度
最差情況:放在頂部
- 會阻塞後面內容的呈現
- 會阻塞其它組件的下載
7、避免使用CSS表達式
why
表達式可能會運算很多遍、影響頁面性能
how
實現動態CSS可以使用javascript控制
$(function () {
$("dom").css("background-color",(new Date()).getHours()%2?"#EEE":"#BBB");
});
8、使用外鏈JavaScript和CSS
why
提高樣式和腳本複用性
注意:純粹而言,內聯速度比外鏈快,因為外鏈額外增加了http請求,但是由於瀏覽器緩存,當多頁面引用了同一個樣式表或腳本文件時,反而減少了HTTP請求,實現複用。
how
<link rel="stylesheet" type="text/css" href="style.css" />
<script type="text/javascript" src="main.js" />
9、減少DNS查找
why
查找DNS是需要花費時間的,通常瀏覽器在查找給定的IP地址要花費20~120毫秒的時間,在DNS完成查找之前,瀏覽器無法從主機名下載任何東西。
how
最理想的情況:只使用一個主機名,既減少了DNS查找,又最大化了並行下載。(只針對頁面組件很少(1個或2個)的情況)
更現實的情況:使用2個,但不多於4個主機名,這樣在減少DNS查找和允許高度並行下載之間做出了比較好的均衡。
10、精簡JavaScript和CSS
why
減小文件大小,改善加載時間
how
- 從代碼中移除不必要的字符(包括空格、註釋、換行符等)
- 精簡JS代碼可使用JSMin
- 精簡CSS代碼,合併相同的類,移除不使用的類,使用縮寫,如“#EEEEEE”寫成“#EEE”,“0px”寫成“0”。
11、避免重定向
why
重定向是指用户的原始請求重新轉向到了其它請求
301 Moved Permanently:這個狀態碼標識用户所請求的資源被移動到了另外的位置,客户端接收到此響應後,需要發起另外一個請求去下載所需的資源。
302 Found:這個狀態碼標識用户所請求的資源被找到了,但不在原始位置,服務器會回覆其他的一個位置,客户端收到此響應後,也需要發起另外一個請求去下載所需的資源。
目前我們一直只要區分301和302即可。他們本質上的區別到底是什麼呢?301表示永久重定向,302表示臨時重定向。
how
在定義鏈接地址的href屬性的時候,儘量使用最完整的、直接的地址。例如:
使用 www.google.com 而不是google.com
使用cn.xxxx.com而不是xxxx.com
使用www.google.com.hk而不是google.com
使用www.site.com/products/而不是www.site.com/products
12、移除重複腳本
why
重複腳本損傷性能:不必要的HTTP請求及執行JS所浪費的時間
how
確保腳本只被加載一次。使用模塊化工具如requireJS或seaJS管理腳本。
13、配置ETag(實體標籤)
它的作用是用一個特殊的字符串來標識某個資源的“版本”,客户端(瀏覽器)請求的時候,比較ETag如果一致,則表示該資源並沒有被修改過,客户端(瀏覽器)可以使用自己緩存的版本,避免重複下載。
服務器檢測緩存組件和原始服務器組件匹配的方式
如果緩存組件過期了或者用户明確地重新加載了頁面,瀏覽器在重用之前必須首先檢查它是否有效。這稱作一個條件GET請求。雖然瀏覽器必須產生這個http請求,但是仍比簡單地下載所有已過期的組件效率高。如果瀏覽器組件是有效的(相互匹配)原始服務器則不會返回整個組件,而是返回304 not modifed狀態碼。
檢測匹配有兩種方式
- 比較最新修改日期
第一次請求響應
————>
GET /i/xx.jpg HTTP 1.1
HOST www.xxx.com
<————
HTTP 1.1 20 OK
Last-Modified:true .12 dec 2015 03:03:09 GMT
Content-Length:1024
第二次請求響應
————>
GET /i/xx.jpg HTTP 1.1
HOST www.xxx.com
If-Modified-Since:True,12 dec 2015 03:03:09 GMT
<————
HTTP 1.1 304 not modifed
- 比較實體標籤
實體是我們之前提到的組件的另一種稱呼。ETag是唯一標識了一個組件的一個特定版本的字符串,必須帶上引號。這種為驗證實體提供了更為靈活的機制——可以根據user-agent,accept-language頭而改變。
第一次請求響應
————>
GET /i/xx.jpg HTTP 1.1
HOST www.xxx.com
<————
HTTP 1.1 20 OK
Last-Modified:true .12 dec 2015 03:03:09 GMT
ETag:"10c34ba-8ba-abds3b3"
Content-Length:1024
第二次請求響應
————>
GET /i/xx.jpg HTTP 1.1
HOST www.xxx.com
If-Modified-Since:True,12 dec 2015 03:03:09 GMT
If-None-Match:"10c34ba-8ba-abds3b3"
<————
HTTP 1.1 304 not modifed
ETag帶來的問題
- 如果部署在服務器場環境中,配置不當的話,可能每個服務器會對相同的資源生成不一樣的ETag,這樣就增加了重複下載的可能性。
ETag的優勢和特點
- 可以更加精確地判斷資源是否被修改,因為它不是一個時間值,而是對時間經過處理的一個長整型數值(當然具體算法我們目前還不得而知)。
- 瀏覽器發起新請求時需要包含 If-None-Match。
14、使Ajax可緩存
why
由於AJAX其實也是需要發起請求,然後服務器執行,並將結果(通常是JSON格式的)發送給瀏覽器進行最後的呈現或者處理,所以對於網站設計優化的角度而言,我們同樣需要考慮對這些請求,是否可以儘可能的利用到緩存的功能來提高性能。
how
對於AJAX而言,有一些特殊性,並不是所有的AJAX請求都是可以緩存的。
- POST的請求,是不可以在客户端緩存的,每次請求都需要發送給服務器進行處理,每次都會返回狀態碼200。(這裏可以優化的是,服務器端對數據進行緩存,以便提高處理速度)
- GET的請求,是可以(並且默認)在客户端進行緩存的,除非指定了不同的地址,否則同一地址的AJAX請求,不會重複再服務器執行,而是返回304。
有的時候,我們可能希望GET請求不被緩存,有幾種做法來達到這樣的目的。
- 每次調用的時候,請求不同的地址(可以在原始地址後面添加一個隨機的號碼)。
- 如果你所使用的是jquery的話,則可以考慮禁用AJAX的緩存。
$.ajaxSetup({ cache: false });
15、使用GET來完成Ajax請求
why
- 1、POST請求,不能使用客户端緩存
- 2、GET請求,可以使用客户端緩存
這個意義上來講,使用GET會比POST而言,因為減少了請求數和數據的重複傳輸,有更好的一個性能表現。
在使用XMLHttpRequest(目前的AJAX都是基於它實現的)的時候,瀏覽器中的POST實現為兩步走的過程,首先發送頭部信息,然後再發送數據。但如果是使用GET的話,就只有一個TCP的包發送出去(除非有大量的Cookie),這樣無疑可以提高性能。
【備註】一個TCP包的尺寸大約為1452字節。 除此之外,顯示的項目中,並不是總能使用GET的,例如長度方面可能會有限制:The maximum URL length in IE is 2K, so if you send more than 2k data you might not be able to use GET.
16、減少DOM元素數量
why
DOM(Document Object Model)文檔對象模型
HTML DOM 定義了訪問和操作 HTML 文檔的標準方法。
DOM 將 HTML 文檔表達為樹結構。
減少頁面的DOM元素數量,有助於減小頁面體積,並且也降低了維護這份DOM樹的成本。
how
- 1、避免不正確地使用服務器控件。
- 2、減少不必要的內容(並不是所有的內容都必須放在頁面上面的)。
如果數據量大,可以考慮分頁,或者按需加載
17、避免404
why
什麼情況下會發生404錯誤?
404 意味着Not Found,意思是説未找到資源。至少會有兩種原因導致404錯誤:
- 1、該資源按理説是要有,但我們沒有提供。用户按照正常的方式來請求,所以資源找不到。
- 2、該資源本來就不存在,用户按照不正常的方式來請求,當然還是找不到。
404錯誤會有什麼影響?
① 看不到的影響:有時候,404錯誤發生了,用户可能根本沒有感覺到。
- 例如請求favicon.ico文件,或者請求了某個不存在的腳本文件、樣式表、圖片文件,頁面還是會按照正常的方式進行呈現。
- 丟失的腳本文件、樣式表、圖片文件,會導致頁面的某些行為、界面效果出現異常(也可能不是很明顯)
- 最大的問題可能是性能方面的影響。尤其是如果請求一個不存在的腳本文件,因為瀏覽器在請求腳本文件的時候,即便是返回404,它也會嘗試去按照Javascript的方式解析響應中的內容。這無疑會增加很多處理的時間,而因為該文件不存在,所以這些都是無用功。
② 看得到的影響:
- 如果用户請求的某個頁面不存在,那麼他將收到明確的迴應
- 默認情況下,他將收到一個標準的錯誤頁面(請注意:不少用户會被這個頁面嚇到)
how
避免404錯誤發生的措施:
- 為網站提供favicon.ico。
- 在發佈網站前的測試工作中,運行Link checker工具,確保所有鏈接都是能夠訪問到的。這個工具是W3C發佈的,完全免費,你值得擁有。
- 為了避免用户收藏絕對地址(customer.aspx),給後期更新帶來隱患。可以考慮在設計階段採用 Url Rewriting 或者 Routing 等技術來實現更加友好和靈活的地址(例如/Customer),以後如果業務邏輯有變化,只需要修改一下路由規則即可。
第三條措施,同樣可以儘可能地減少用户手工輸入地址出錯的機會。
18、減少Cookie的大小
why
如果對某個域(Domain)保存了Cookie,那麼針對這個域的所有請求,都會發送這些所有的Cookie(哪怕當前請求根本用不着,例如針對圖片的請求),大量的、重複的發送Cookie毫無疑問會增加網絡的流量,並因此而降低請求被執行的性能。
how
從技術上説,這個文件的內容是由網站控制的,它可以決定要寫什麼內容在裏面,他也可以決定是否要加密。唯一的一個限制,這個文件的體積不允許超過4KB。
19、使用無Cookie的域
why
比如圖片 CSS 等,Yahoo! 的靜態文件都在主域名以外,客户端請求靜態文件的時候,減少了 Cookie的反覆傳輸對主域名的影響。
只有訪問主域名的時候才需要保存cookie,而cookie會自動地發送給當前域的所有請求。
20、不要使用濾鏡
why
Filters這個功能是IE當年為了提供更加豐富的一些頁面效果而設計出來的。
不僅僅是別的瀏覽器可能不支持,IE從9.0版本開始也放棄了這方面的支持。
21、不要在HTML中縮放圖片
why
有時得到的圖片尺寸和具體顯示尺寸不一樣,為了在網頁中顯示出希望的尺寸,通常會通過下面的方法把圖片進行縮放:
<img width="100" height="100" src="pic.jpg" alt="my pic"/>
瀏覽器下載到原始圖片之後,如果原始尺寸與目標尺寸不符,就會需要對圖片進行縮放(拉伸或者縮小),以便實現剛才所提到的目的。
how
我們需要在網頁中顯示什麼尺寸的圖片,就請圖片設計人員提供什麼尺寸的圖片,而不是在網頁中進行縮放。
22、縮小favicon.icon並緩存
why
- 1、每個網站都應該有該文件,瀏覽器在訪問任何頁面的時候,總是會嘗試去請求這個文件(如果本地沒有的話)。
- 2、該文件通常應該命名為favicon.ico ,如果希望使用別的名稱或者格式(例如PNG),則需要在頁面的頭部(Head)中定義引用(下面兩句中的第一句是必須的)
<link rel="shortcut icon" href="http://example.com/favicon.ico" type="image/vnd.microsoft.icon">
<link rel="icon" href="http://example.com/favicon.ico" type="image/vnd.microsoft.icon">
- 3、該文件可以直接放在網站根目錄,但也可以放在其他的主機,或者你想要的任何位置。如果不在默認的根目錄下面,也是需要通過上面所提到的引用方式定義。
how
使它儘量在1KB左右。想比較其他的格式(PNG,GIF等),該文件默認的格式為ico,這種文件通常較小。要創建favicon.ico文件,可以使用 http://www.favicon.cc/ 提供的在線免費服務。
使它能夠緩存。 由於該文件使用很頻繁,所以緩存顯得很重要。對於這個文件而言,可以設置永不過期(或者過期時間長一些)。
將該文件放在單獨的主機中,可以避免在請求該文件時發送cookie。
23、避免空的src和href
why
空的src和href都會導致多餘的HTTP請求,雖然不影響加載時間,但是會對服務器產生不必要的流量和壓力,嚴重的以至於影響整個網站的用户體驗。
例子:
在頁面加載的過程中,一個有着空src屬性的img元素被JavaScript動態地賦值。這樣做的問題是,在腳本執行之前元素就被瀏覽器渲染了(尤其是當你把腳本放到文檔最後的時候)。所以瀏覽器依然會發起一個HTTP 請求,雖然它是一個空值。
雅虎的團隊指出,如果你將img的src留空,可能你的本意是暫時不要顯示任何圖片,但在不同的瀏覽器其實還是會有一些額外的請求發生。
例子:
同樣的問題也發生在href 這個屬性上。有些時候,開發人員想用超鏈接來觸發JavaScript的一個交互。這時問題就來了,當用户觸發了“單擊”操作,如果 href 是空的那麼瀏覽器就向服務器發送一個HTTP 請求。
how
- 避免空的src和herf值。
- 解決留空src屬性的問題:
- 你可以將初始圖片設置為一個很小的默認圖片(這個圖片設置永不過期),而不是留空。
解決留空href屬性的問題:
- 給
<a>標籤以href屬性,並不連接到實際的頁面:
<a href="#"></a>
<a href="#nogo"></a>
<a href="##"></a>
<a href="###"></a>
<a href="void(0);"></a>
<a href="void(0)"></a>
<a href=";"></a>
<a href=""></a>
- 禁止跳轉,並添加
cursor:pointer樣式
<style type="text/css">
a{cursor: pointer}
</style>
<a>點擊一</a>
<a onclick="doSomething()">點擊二</a>
- 給
a標籤創建一個帶有描述信息的href屬性,並監控click事件調用preventDefault()函數。
<a href="#Something_De scriptive" id="my_id">Trigger</a>
<script>
$("#my_id").click(function(e){
e.preventDefault(); // 取消單擊事件的默認動作以阻止鏈接的跳轉。
// 其他的代碼
});
</script>
優點:
讓<a>夠響應鍵盤事件並獲得焦點(從而屏幕閲讀器能夠讀出背後的內容,增強可訪問性)
優雅降級,在網絡連接很差,還沒有加載到CSS的時候,<a>依然有手型與正常的link樣式。
參考:YSlow團隊的23條“Web性能最佳實踐和規則”+《高性能網站建設指南》