減少HTTP請求
圖片地圖
// 示例代碼
<img usemap="#map1" src="...">
<map name="map1">
<area shape="rect" coords="0,0,31,31">
...
</map>
CSS Sprites
合并圖片,使用CSS背景定位蝴猪。
內(nèi)聯(lián)圖片
通過使用data:URL模式可能在web頁面上包含圖片但無需任何額外的HTTP請求。
data:URL除了可以用于內(nèi)聯(lián)圖片留搔,還可以用在任何需要指定URL的地方煎楣,包括script和a標(biāo)簽。
缺點是不受IE支持羡榴,另外可能存在數(shù)據(jù)大小上的限制。
由于data:URL是內(nèi)聯(lián)在頁面上的运敢,在跨越不同頁面時不會被緩存校仑。在這種情況下忠售,聰明的作法是使用CSS并將內(nèi)聯(lián)圖片作為背景。將該CSS規(guī)則放在外部樣式表中迄沫,這意味著數(shù)據(jù)可以緩存在樣式表內(nèi)部稻扬。
合并腳本和樣式表
在開發(fā)環(huán)境下分模塊,在生產(chǎn)環(huán)境下合并腳本和樣式表羊瘩。
使用內(nèi)容發(fā)布網(wǎng)絡(luò)(CDN)
只有10% ~ 20%的最終用戶響應(yīng)時間花在下載HTML文檔上泰佳。其余的80% ~ 90%時間花在了下載頁面中的所有組件上。
使用CDN將組件Web服務(wù)器分散開(組件服務(wù)器離用戶距離越近尘吗,響應(yīng)時間越短)逝她,不僅能達到響應(yīng)時間大幅減少的目的,而且還很容易實現(xiàn)睬捶。
添加Expires頭
Web服務(wù)器使用Expires頭來告訴Web客戶端它可以使用一個組件的當(dāng)前副本黔宛,來減少HTTP請求。
Expires: Mon, 15 Apr 2024 20:00:00 GMT
Cache-Control: max-age
Expires頭使用一個特定的時間擒贸,它要求服務(wù)器跟客戶端嚴(yán)格同步臀晃。HTTP1.1引入了cache-control頭來克服Expires頭的限制。
Cache-Control使用max-age指定組件被緩存多久介劫,一個長久的的max-age頭可以將刷新窗設(shè)置為未來10年徽惋。
Cache-Control: max-age=315360000
Expires-Default
Apache模塊的mod_expires提供Expires-Default指令同時向響應(yīng)中發(fā)送Expires頭和Cache-Control max-age頭。(跨瀏覽器改善緩存的最佳解決方案)
當(dāng)我們需要更改緩存中的文件時蜕猫,最有效的解決方案是修改其鏈接,這樣哎迄,全新的請求將從服務(wù)器下載最新的內(nèi)容回右。雅虎的做法是將版本號嵌入文件名中。
當(dāng)我們沒有使用Expires頭時漱挚,瀏覽器也會有緩存翔烁,只不過瀏覽器會向服務(wù)器發(fā)送一條GET請求,確定是否要使用緩存中文件旨涝。
壓縮組件
從HTTP1.1開始蹬屹,Web客戶端可以通過HTTP請求中的Accept-Encoding頭來表示對壓縮的支持:
Accept-Encoding: gzip, deflate
如果Web服務(wù)器看到請求中有這個頭,就會使用客戶端列出來的方法中的一種來壓縮響應(yīng)白华。Web服務(wù)器通過響應(yīng)中的Content-Encoding來通知Web客戶端:
Content-Encoding: gzip
代理緩存
可以通過設(shè)置Vary: Accept-Encoding讓代理服務(wù)器緩存壓縮和未壓縮的響應(yīng)慨默,以滿足不同瀏覽器的需求(瀏覽器是否支持如gzip)。
邊緣情形
發(fā)送內(nèi)容到不支持它的客戶端弧腥,忘記將壓縮內(nèi)容聲明為已經(jīng)進行了gzip編碼等厦取,頁面都會被破壞。
- 如果你的網(wǎng)站用戶很少管搪,并且他們處在一個小圈子中(例如虾攻,他們在一個intranet中铡买,或者都使用Firefox 1.5)邊緣情形瀏覽器就不需要太多關(guān)注■浚可以壓縮內(nèi)容并使用Vary:Accept-Encoding奇钞。這樣可以通過減少組件的大小和利用代理緩存來改善用戶體驗。
- 如果你更注意帶寬開銷漂坏,可以和前一種情況一樣——壓縮內(nèi)容并使用Vary: Accept-Encoding景埃。這降低了服務(wù)器端的帶寬開銷并提升了代理處理的請求數(shù)量。
- 如果你擁有大量的樊拓,多變的用戶群纠亚,能夠應(yīng)付較高的帶寬開銷,并且享有高質(zhì)量的名聲筋夏,請壓縮內(nèi)容并使用Cache-Control: Private蒂胞。這禁用了代理緩存但避免了邊緣情形缺陷。
將樣式表放在頂部
在IE中条篷,將樣式表放在底部會導(dǎo)致出現(xiàn)“白屏”骗随。
一個style塊可以包含多個@import規(guī)則,但@import規(guī)則必須放在所有其他規(guī)則之前赴叹。
<style>
@import url("styles2.css");
</style>
@import規(guī)則也有可能會導(dǎo)致白屏現(xiàn)象鸿染,因為使用@import規(guī)則會導(dǎo)致組件下載時的無序性。即便把@import規(guī)則放在文檔的HEAD標(biāo)簽中也是如此乞巧。
無樣式內(nèi)容的閃爍
把樣式表放在最后的情況:頁面加載時涨椒,文字首先顯示,然后是圖片绽媒,最后在樣式表正確地下載并解析之后蚕冬,已經(jīng)呈現(xiàn)的文字和圖片要用新的樣式重繪了,這就是“無樣式內(nèi)容的閃爍”是辕。而白屏現(xiàn)象正是對這個問題的彌補囤热。
將腳本放在底部
下載腳本時并行下載實際上是被禁用的,即使使用了不同的主機名获三,瀏覽器也不會啟動其他的下載旁蔼。其中一個原因是,腳本可能使用document.write來修改頁面內(nèi)容疙教,因此瀏覽器會等待棺聊,以確保頁面能夠恰當(dāng)?shù)夭季帧?/p>
在下載腳本時瀏覽器阻塞并行下載的另一個原因是為了保證腳本能夠按照正確的順序執(zhí)行。如果并行下載多個腳本贞谓,就無法保證響應(yīng)是按照特定順序到達瀏覽器的躺屁。
避免CSS表達式
使用外部JavaScript和CSS
內(nèi)聯(lián)的JavaScript和CSS可以減少額外的HTTP請求,但是使用外部的JavaScript和CSS有機會被瀏覽器緩存起來经宏,在這種情況下犀暑,HTML文檔會比使用內(nèi)聯(lián)的HTML文檔小驯击,而且不會增加HTTP請求的數(shù)量。
使用外部JavaScript和CSS能提高組件重用率耐亏,并且易維護徊都。
對于很多網(wǎng)站的主頁來說,使用內(nèi)聯(lián)JavaScript和CSS會是更好的選擇广辰。然后在主頁加載完成后下載其余頁面的外部JavaScript和CSS暇矫,使其被瀏覽器緩存起來。
動態(tài)內(nèi)聯(lián)是指服務(wù)器根據(jù)cookie生成有內(nèi)聯(lián)樣式的頁面或有外部鏈接的頁面择吊。
減少DNS查找
DNS是將域名映射到IP地址李根,而這個查找過程需要時間。
通常大型網(wǎng)站會使用不同的主機几睛,以提供更多的并行下載房轿,這樣頁面相對能夠更快地展示給用戶。但是越多的主機所森,意味著需要更多的DNS查找囱持。
精簡JavaScript
避免重定向
重定向引起的延遲也很嚴(yán)重,因為它延遲了整個HTML文檔的傳輸焕济。在HTML文檔到達之前纷妆,頁面中不會呈現(xiàn)任何東西,也沒有任何組件會被下載晴弃。
URL的結(jié)尾沒有斜線會導(dǎo)致一次重定向掩幢,這個是可以人為避免的。但是主機后缺少斜線時不會發(fā)生重定向上鞠,如http://www.yahoo.com际邻,你會發(fā)現(xiàn)瀏覽器地址欄會在結(jié)尾自動添加斜線。這是因為瀏覽器在進行GET請求時必需指定路徑旗国。如果沒有路徑枯怖,它就會簡單的使用文檔根(/)
刪除重復(fù)腳本
在一個頁面中兩次包含同一個JavaScript文件會損傷性能注整,因為會產(chǎn)生不必要的HTTP請求(IE)和執(zhí)行JavaScript所浪費的時間(腳本會被多次求值)能曾。
在IE中,被緩存的文件還會發(fā)送條件GET請求肿轨,以確定緩存中的文件是否需要更新寿冕。
配置ETag
ETag(Entity Tag,實體標(biāo)簽)是Web服務(wù)器和瀏覽器用于確認(rèn)組件有效性的一種機制椒袍。
瀏覽器下載組件時驼唱,會將它們存儲到緩存中。在后續(xù)的頁面瀏覽中驹暑,如果緩存的組件是“新鮮的”玫恳,瀏覽器就會從磁盤上讀取它辨赐,避免產(chǎn)生HTTP請求。如果組件沒有過期京办,那它就是“新鮮的”掀序,這取決于Expires頭。
如果緩存過期了惭婿,瀏覽器必須檢查它是否還有效不恭,這時,瀏覽器會發(fā)送一個條件GET請求到服務(wù)器上進行確認(rèn)财饥。如果緩存有效换吧,則會返回304 Not Modified的狀態(tài)碼。
檢查組件是否有效有兩種方式:
- 比較最新修改日期
- 比較實體標(biāo)簽
瀏覽器緩存在組件和最新的修改日期钥星,下次請求時沾瓦,會使用If-Modified-Since頭將最新修改日期到服務(wù)器上比較
實體標(biāo)簽就是比較緩存中的組件與原始服務(wù)器上的組件是否匹配。ETag提供了比最新修改日期更為靈活的機制打颤,因為它可以使用組件的一些屬性來構(gòu)造暴拄。使用If-None-Match頭將ETag發(fā)送到服務(wù)器上比較。
ETag的問題是其對于服務(wù)器的唯一性编饺,在服務(wù)器集群中乖篷,很難做到有效的驗證。所以相同的組件在不同的服務(wù)器透且,收到的可能就不是304響應(yīng)撕蔼,而是200響應(yīng),因此會下載組件的所有數(shù)據(jù)秽誊。
ETag還降低了代理緩存的效率鲸沮。代理后面用戶緩存的ETag經(jīng)常和代理緩存的ETag不匹配,這導(dǎo)致不必要的請求被發(fā)送到原始服務(wù)器锅论。
而且If-None-Match比If-Modified-Since優(yōu)先級高讼溺。如果請求中同時出現(xiàn)這兩個頭,則原始服務(wù)器會禁止返回304最易,除非請求中的條件頭字段全部一致怒坯。實際上如果根本沒有If-None-Match頭反而會更好一些。
即便組件具有長久的Expires頭藻懒,一旦用戶單擊了Reload或Refresh按鈕剔猿,仍然會產(chǎn)生條件GET請求。
使Ajax可緩存
使Ajax可緩存嬉荆,除了使用Expires頭之外归敬,最好的方式是使用查詢子符串參數(shù),如:
/ws/mail/v1/formrpc?m-GetMessage&yid=steve_souders