本文根據(jù)《高性能網(wǎng)站建設(shè)指南》《High Performance Web Sites》,一書進行總結(jié),加上自己的理解和新的知識點進行補充添加。這些原則大多數(shù)都非常實用,適合站點架構(gòu)師、前端工程師。其中對于前端工程師的意義更大一些。

規(guī)則1——減少HTTP請求
只有10%到20%的最終用戶響應(yīng)時間花在接收請求的HTML文檔上面。剩下80%到90%的 時間花在為HTML文檔所引用的所有組件(圖片,腳本,flash,樣式表等)進行的HTTP請求上。因此改善響應(yīng)的最簡單途徑就是減少組件數(shù)量,由此減少HTTP請求的數(shù)量。
圖片地圖
使用map標簽進行坐標定位,減少圖片數(shù)量。導(dǎo)航欄中使用了多個圖片時候可以使用。
缺點很多:手工方式很難完成坐標定位,且容易出錯。除了矩形之外也難以定義其他形狀,通過DHTML定義的圖片IE中還無法工作。不建議使用。
CSS Sprites (雪碧圖/精靈圖)
通過把多個圖片合并到一個圖片,然后利用background-position進行定位,比使用分離圖片快50%。圖片地圖中的圖片必須是連續(xù)的,而CSS Sprites則沒有這個限制。也有人認為合并后的圖片比分離的圖片總和還要大,合并后的圖片包含附加的空白區(qū)域。實際是變小的,雪碧圖降低了圖片自身的開銷。(顏色表,格式信息,等等)
如果頁面中背景,按鈕,導(dǎo)航欄,鏈接需要使用很多圖片,可以使用。優(yōu)點——干凈的標簽,很少的圖片和很短的響應(yīng)時間。
缺點:后期修改麻煩,難以維護,牽一發(fā)動全身,沒有之前改一個圖片就好了容易
雪碧圖制作方法:
-
百度搜索CSS Sprites 可找到相應(yīng)制作軟件軟件下載地址
-
gulp等自動化工具,自動合成
-
ps自己制作

內(nèi)聯(lián)圖片
使用 data:URL的模式在WEB頁面中包含圖片,但無需任何額外的HTTP請求。我們都熟悉http:模式的URL。其他類似模式包括ftp:,file:和maito:
data:url模式
在1995年提出來:允許將小數(shù)據(jù)塊內(nèi)聯(lián)為立即數(shù),數(shù)據(jù)就在url自身中。
什么是內(nèi)聯(lián)圖片
內(nèi)聯(lián)圖片是一種新型的圖像格式(在我看來是這樣不知道理解對否),官方稱為:data URI scheme。通常我們存儲的圖片在網(wǎng)頁中需要寫:
<img src="http://www.registerjl.com/images/mna5.jpg"/>
而內(nèi)聯(lián)圖片寫法會是
<img src="data:image/png;base64,iVAGRw0KGDCFGNSUhEUgACBBQAVGADCAIATYJ7ljmRGGAAGElEVQQIW2P4DwcMDAxAfBvMAhEQMYgcACEHG8ELxtbPACCCTElFTEVBQmGA"/>
內(nèi)聯(lián)圖片語法
<img src="data:image/png;base64,iVBOR....>
-
data - 取得數(shù)據(jù)的協(xié)定名稱
-
image/png - 數(shù)據(jù)類型名稱
-
base64 - 數(shù)據(jù)的編碼方法
-
iUANR.... - 編碼后的數(shù)據(jù)
-
: , ; - data URI scheme 指定的分隔符號
這種圖片格式無需額外的HTTP請求是不錯,但是還有一個重要的一點,瀏覽器不會緩存這種圖像。 data url 節(jié)省了HTTP請求,但是如果這個圖像在網(wǎng)頁多個地方顯示會加大網(wǎng)頁的內(nèi)容,延長下載時間。還有一點 IE8 以下都不支持這種圖像,所以還是IE6的用戶就比較悲催了。并且超過 100kb 圖像使用base64編碼也會增大圖片大小。導(dǎo)致網(wǎng)頁整體下載量增加。 (BASE64編碼圖片導(dǎo)致網(wǎng)站瀏覽緩慢崩潰但是很多聰明人做法是把背景平鋪類圖片作為內(nèi)聯(lián)圖片使用,這樣效果很不錯。也減少了HTTP請求加快了網(wǎng)站速度。那么你可能會問到如何獲取圖片的base64編碼呢。網(wǎng)絡(luò)上有很多免費的base編碼和解碼工具,但是有個最簡單方法就是我們寫一個PHP文件。使用base64_encode()進行編碼:比如:
echo base64_encode(file_get_contents('211-11.JPG'));
如何解決網(wǎng)頁下載延遲問題。最簡單一個方法就是用寫成CSS里的背景去調(diào)用CLASS 類名就可以了。比如咱們用上面的例子:
.blogxmao{background:url(data:image/png;base64,iVAGRw0KGDCFGNSUhEUgACBBQAVGADCAIATYJ7ljmRGGAAGElEVQQIW2P4DwcMDAxAfBvMAhEQMYgcACEHG8ELxtbPACCCTElFTEVBQmGA")}
<div>..內(nèi)容...</div><div>..內(nèi)容...</div>
合并腳本和樣式表
根據(jù)模塊化原則, 我們應(yīng)該將代碼放到多個小文件中,但是這樣會降低性能,因為每個文件都會導(dǎo)致一個額外的http請求。理想情況,一個頁面不應(yīng)該使用多余一個的腳本和樣式表。世界前十網(wǎng)站腳本和樣式表一般不超過2個。
使用模塊化工具,比如seajs,requirejs進行優(yōu)化。不然隨著文件的增多,手動合并將會很麻煩。
規(guī)則2——使用內(nèi)容分發(fā)網(wǎng)絡(luò) CDN
內(nèi)容分發(fā)網(wǎng)絡(luò)(conten delivery network)是一組分布在多個不同地理位置的Web服務(wù)器??梢允褂肅DN服務(wù)提供商。

CDN優(yōu)點:
縮短相應(yīng)時間,備份擴展存儲能力和進行緩存,緩和WEB流量峰值壓力(獲取天氣,娛樂體育新聞等等)
CDN缺點:
你的響應(yīng)時間會受到其他網(wǎng)站——甚至是競爭對手的流量的影響。無法控制組件服務(wù)器所帶來的特殊麻煩。比如,修改HHTP表頭必須由服務(wù)提供商來完成。
如果CDN服務(wù)性能下降了,你的工作也會受到影響。當然你可以使用兩個CDN服務(wù)提供商。
CDN用于發(fā)布靜態(tài)圖片(將所有靜態(tài)組件轉(zhuǎn)移到CDN),圖片,腳本樣式表,F(xiàn)lash,靜態(tài)文件更易存儲,有較少的依賴性。
規(guī)則3——添加Expires頭
Web頁面包含大量組件,首次訪問時間并不是唯一需要考慮的,頁面的初訪者會進行很多HTTP請求,但是可以使用一個長久的Expires頭,使得這些組件被緩存。
Expires頭
長久的expires經(jīng)常用于圖片,然而可以用于所有組件,很多頂級網(wǎng)站并沒有做到這一點,因為添加長久的ecpires頭會帶來額外的開發(fā)成本。
Expires:Mon,15 Apr 2025 00:00:00 GMT
它會告訴瀏覽器該響應(yīng)的有效性會持續(xù)到2025年。
Max-Age 和mod_expires
因為expires使用一個特定的時間,要求客戶端和服務(wù)器端時鐘嚴格同步,過期日期需要檢查,還要配置新的日期,所以使用麻煩。HTTP1.1引入了Cache-Control頭來克服它的限制。Cache-Control使用max-age指令來指定組件被緩存多久。以秒為單位定義了一個更 新窗。
對于不支持HTTP1.1的瀏覽器,你可以同時指定兩個響應(yīng)頭——Expires和max-age.如果兩者同時出現(xiàn),后者將會重寫前者。如果你很盡責(zé),你仍然會擔心Expires過期問題以及時鐘同步問題。
幸運的是,mod_expires使你通過ExpirsDefault指令以相對方式設(shè)置日期。
ExpirsDefault 'access plus 10 years'
時間可以設(shè)置為年月日時分秒。它同時向響應(yīng)中發(fā)送Expires頭和max-age頭。實際過期日期根據(jù)何時得到請求而變,但是max-age有優(yōu)先權(quán)。時鐘同步問題和固定日期更新不用擔心了。
跨瀏覽器改善緩存最佳方案就是使用 ExpirsDefault設(shè)置的Expires.
空緩存vs完整緩存
用戶第一次訪問你的網(wǎng)站它不會對HTTP的請求的數(shù)量產(chǎn)生任何影響。此時瀏覽器的緩存是空的。性能改進取決于是否有完整緩存。
在那些每日一次一更新的網(wǎng)站,帶有完整緩存的頁面瀏覽百分比很少。
旅游網(wǎng)站,email網(wǎng)站中每個用戶會話可能產(chǎn)生多次頁面瀏覽,百分比就高。
只要用戶每個月至少訪問一次,或者每次會話產(chǎn)生多次頁面瀏覽,完整緩存就很有用,使用長久Expires就很有必要。
不僅僅是圖片
腳本,樣式表,flash都可以緩存,但是HTML文檔不應(yīng)該使用,因為包含動態(tài)內(nèi)容,每次都要更新。
大型網(wǎng)站,圖片,樣式表,腳本大部分都要緩存30天以上。但是經(jīng)常需要變化的新聞圖片等等,不應(yīng)該使用。我們可以查看Last-Modifed中的值來看改變時間以及頻率。
修訂文件名
使用長久的Expires缺點是 :瀏覽器不會檢查任何更新,直到過了過期日期。即使在服務(wù)器上更新了組件,瀏覽器因為緩存也不能獲得最新組件。
為了確保用戶能獲得更新過的組件,需要在所有HTML頁面中修改組件的文件名。
最有效的解決方案是修改其所有鏈接,這樣。全新的請求將從原始服務(wù)器下載最新的內(nèi)容。
使用php等動態(tài)語言生成HTML頁將很簡單,為所有組件的文件名使用變量,使用這種方法,在頁面中更新文件名只需要簡單地在某個地方修改變量。Yahoo經(jīng)常將這一步作為生成過程的一部分——版本號嵌入在組件的文件名中(例如yahoo_2.0.6.js),而且在全局映射中修訂過的文件名會自動更新。嵌入版本號不僅可以改變文件名,還能在調(diào)試中更容易找到準確的源代碼文件。
規(guī)則4——壓縮組件
規(guī)則1--3都是限制不必要的HTTP請求來減少響應(yīng)時間,現(xiàn)在我們通過減少響應(yīng)大小來減少響應(yīng)時間。
壓縮是如何工作的
用于減小文件體積的文件壓縮已經(jīng)在email應(yīng)用和ftp站點中使用了十年,同樣的技術(shù)也可以用于向瀏覽器發(fā)布壓縮的web頁面。
從HTTP1.1開始,web客戶端可以通過請求中的Accept-Encoding頭來表示對文件壓縮的支持。
————>
Accept-Encoding:gzip
如果web服務(wù)器看到請求中有這個頭,就會使用客戶端列出來的方法中的一種來壓縮響應(yīng)。并通過響應(yīng)中的Content-Ecoding來通知客戶端。
<————
Content-Ecoding:gzip
gzip是目前最有效,最流行的壓縮方法,免費模式,并被標準化為RFC 1952.(90%使用)
壓縮什么
很多網(wǎng)站會壓縮HTML文檔,壓縮腳本和樣式表也是非常值得的,還包括XML和JSON在內(nèi)的任何文本響應(yīng)。圖片和PDF不應(yīng)該解壓縮,因為已經(jīng)被壓縮了。再壓縮只會浪費CPU資源,還有可能會增加文件大小。
壓縮的成本:服務(wù)器會花費額外的CPU周期來完成壓縮,客戶端要對壓縮文件進行解壓縮。要檢測受益是否大于開銷,需要考慮響應(yīng)的大小,連接的帶寬和和客戶端服務(wù)器之間的Internet距離。
根據(jù)經(jīng)驗,通常對大于1KB或2KB的文件進行壓縮。mod_gzip_minimum_file_size指令控制著希望壓縮文件的最小值,默認值是500B。
美國十大流行網(wǎng)站中9個壓縮了html,七個壓縮了大多數(shù)腳本和樣式表,只要五個壓縮了所有腳本和樣式表。這可以將頁面減少70%。
節(jié)省
壓縮之后能將響應(yīng)整體減少60%左右
配置
配置gzip時使用的模塊取決于Apache(intert上最流行的web服務(wù)器,份額70%以上)的版本。Apache1.3使用mod_gzip,2.3使用mod_deflate.
具體配置詳情如何壓縮,壓縮哪些文件,壓縮程度,類型(可使用正則匹配)可搜索mod_gzip的網(wǎng)站參考。
規(guī)則5——將樣式表放在頂部
使用link標簽將樣式表放在文檔head中
白屏
將css放在底部的時候(有觀點覺得DHTML特性東西在最后展現(xiàn),所以會把css放在底部覺得更優(yōu)化。)實則不然,這樣容易發(fā)生白屏和無樣式內(nèi)容的閃爍。
DHTML不是 W3C 標準
DHTML 指動態(tài) HTML(Dynamic HTML)。
DHTML 是一個營銷術(shù)語 - 被網(wǎng)景公司(Netscape)和微軟公司用來描述 4.x 代瀏覽器應(yīng)當支持的新技術(shù)。
DHTML 是一種用來創(chuàng)建動態(tài)站點的技術(shù)組合物。
對大多數(shù)人來說,DHTML 意味著 HTML 4.0、樣式表以及 JavaScript 的結(jié)合物。
W3C 曾講過:“動態(tài)HTML是一個被某些廠商用來描述可使文檔動態(tài)性更強的HTML、樣式表以及腳本的結(jié)合物的術(shù)語。”
比如一些打字機效果文字,閃爍文字,遮罩濾鏡等等。
白屏容易產(chǎn)生的地方,特別是在IE中:
-
新窗口中打開時
-
重新加載時
-
作為主頁(打開新的瀏覽器窗口)
無樣式內(nèi)容的閃爍FOUC
FOUC flash of unstyles content 產(chǎn)生原因是沒有吧樣式表放在head頂部,或者使用了@import導(dǎo)入(即便放在前面了,樣式表還是會最后下載)
所以避免無樣式內(nèi)容閃爍最好方法就是使用link標簽將其放在head頂部
規(guī)則6——將腳本放在底部
腳本放在頂部會阻塞后面內(nèi)容的呈現(xiàn)和組件的下載。進而產(chǎn)生白屏現(xiàn)象。
放在底部將會產(chǎn)生最小影響和最佳效應(yīng)。

規(guī)則7——避免css表達式
css表達式 expression方法被其他瀏覽器忽略,IE支持,這種方法雖然強大但是非常危險。
表達式求之的頻率遠高于人們的期望,不僅在頁面呈現(xiàn)和大小改變時求值,鼠標拖拽,頁面滾動時候都會求值。所以要避開css表達式,用事件處理器來為特定的事件提供所期望的動態(tài)行為。
規(guī)則8—— 使用外部的js和css
**內(nèi)聯(lián)VS外置**
單純比較而言,內(nèi)聯(lián)在第一次加載時要快一點,因為內(nèi)聯(lián)只有一個http請求。
但是多方面考慮還是要用外置。
內(nèi)聯(lián)無法緩存,外置可以緩存,而且當你頁面使用了相同的js和css時候,可以組件重用,緩存優(yōu)勢更明顯。
最重要的是,外置可以降低耦合度,調(diào)試更加方便~~~
規(guī)則9——減少DNS查找
Internet通過IP地址查找服務(wù)器,瀏覽器查找一個給定主機名的IP地址要花費20—120毫秒,也是有開銷的,充當這個角色的就是DNS(domain name system)
如何減少DNS查找
使用較少的域名,谷歌只有一個,因為只有兩個組件,可以一次并行下載完,兩個主機是最好的,平衡并行下載和DNS查詢。

在HTTP請求中使用 Connection:keep-alive 來保持持久連接。早期HTTP請求中。每個請求都要打開一個socket連接,因為頁面中很多請求收拾指向同一個服務(wù)器,所以這樣效率很低。持久連接的引入使得瀏覽器可以在一個單獨的連接上進行多個請求。
HTTP1.1中定義的管道可以在一個單獨的socket上發(fā)送多個請求而無需等待響應(yīng),而且性能優(yōu)于持久連接。
規(guī)則10——精簡javascript
精簡
精簡是從代碼中移除不必要的字符以減小其大小。進而改善加載時間的實踐。
代碼精簡之后所有的注釋以及不必要的空白字符(空格,換行,制表符),可以減小20%。
混淆
混淆是可以應(yīng)用在源代碼上的另外一種優(yōu)化方式,和精簡一樣,也會移除注釋和空白,作為改寫的一部分,函數(shù)和變量的名字將被轉(zhuǎn)換為更短的字符串。
這樣的代碼更加精煉,但是更難閱讀。通常這樣做是為了增加對代碼進行反向工程的難度,但對提高性能也有幫助。
混淆js的三個缺點
-
缺陷:混淆更加復(fù)雜,混淆過程本身很有可能引入錯誤。
-
維護: 由于混淆會改變js符號,因此需要對任何不能改變的符號(例如API函數(shù))進行標記,防止混淆修改他們。
-
調(diào)試:很難閱讀,調(diào)試更加困難。
精簡從來不會帶來問題,但是混淆會帶來很多問題和缺陷。維護龐大的js建議使用精簡而不是混淆。
實際經(jīng)過gzip壓縮之后,精簡和混淆差別很小。
精簡css
精簡css帶來的節(jié)省通常小于js,因為注釋和空白比較少。最大的潛在節(jié)省來自于優(yōu)化css——合并相同的類,移除不使用的類等。css依賴順序的本質(zhì)(成為層疊樣式表的原因)決定了這是一個復(fù)雜的問題。這個領(lǐng)域還需要進一步的研究和工具開發(fā)。
通常解決方案有使用顏色縮寫,用0代替0px。
原則11 盡量避免重定向
一次重定向意味著在你真正訪問到想要看到的頁面前加入了一輪額外的HTTP請求(客戶端發(fā)起HTTP請求→HTTP服務(wù)器返回重定向響應(yīng)→客戶端對新URL發(fā)起請求→HTTP服務(wù)器返回內(nèi)容,下劃線部分為額外的請求),因此消耗更多的時間(也就給人反應(yīng)更慢的感覺)。因此除非必要,不要隨意使用重定向。幾個“必要”的情況:

1. 避免URL失效
舊站點遷移后,為了避免舊的URL失效,通常將對舊URL的請求重定向至新系統(tǒng)的對應(yīng)地址。
2. URL美化
在可讀性好的URL與實際資源URL之間轉(zhuǎn)換,例如對于Google Toolbar,用戶記得住http://toolbar.google.com這個對人類富有語義的地址,卻很難記住http://www.google.com/tools/firefox/toolbar/FT3/intl/en/index.html這個真正的資源地址。因此有必要保留前者,并且將對前者的請求重定向至后者。
原則12 移除重復(fù)的腳本
不要在一個頁面中重復(fù)引入相同的腳本。例如腳本B和C都依賴于A,那么在使用了B和C的頁面中就有可能存在對A的重復(fù)引用。解決方法,對于簡單的站點手動檢查依賴性,消去重復(fù)引入;對于復(fù)雜的站點則需要構(gòu)建自己的依賴管理/版本控制機制。
原則13 小心處理ETag
ETag是除Last-Modified之外的另一種HTTP Cache手段。通過hash的辦法辨識資源是否被修改。但ETag存在一些問題,例如:
1. 不一致:不同Web服務(wù)器(Apache, IIS等)定義的ETag格式不同
2. ETag的計算是不穩(wěn)定的(由于考慮過多因素),例如:
1) 相同資源在不同服務(wù)器上計算出來的ETag不一樣,而大型Web應(yīng)用通常由不止一臺服務(wù)器提供服務(wù),這就導(dǎo)致客戶端在服務(wù)器A緩存好的資源明明仍然有效,而在下次請求B時由于ETag不同而被認定為失效,導(dǎo)致相同資源的重復(fù)傳輸。
2) 資源不變,而由于一些其他因素的變化,例如配置文件更改,導(dǎo)致ETag變化。直接后果是系統(tǒng)更新后客戶端大規(guī)模發(fā)生Cache失效,導(dǎo)致傳輸量大增,站點性能下降。
作者給出的建議是:要么根據(jù)你的應(yīng)用特點改進已有的ETag計算方法,要么干脆就不用ETag,而改用最簡單的Last-Modified。
原則14 在Ajax中利用HTTP Cache
Ajax是異步請求,異步請求不會阻塞你現(xiàn)在的操作,而且當請求完成時,你馬上就可以看到結(jié)果。但異步不代表能夠瞬時完成,也不代表能夠容忍它花無限多的時間完成。因此對于Ajax請求的性能也需要重視。有很多Ajax請求訪問的是一些相對穩(wěn)定的資源,因此別忘了對Ajax請求利用好HTTP Cache機制,具體參見原則3、13。