Yahoo對(duì)Web前端優(yōu)化的14條經(jīng)驗(yàn)拔萃

規(guī)則1——減少HTTP請(qǐng)求(Minimize HTTP Requests)
只有10%~20%的最終用戶響應(yīng)時(shí)間花在接收請(qǐng)求的HTML文檔上,剩下的80%~90%時(shí)間都花在HTML文檔所引用的所有組件(圖片、腳本、樣式表、Flash等)進(jìn)行的HTTP請(qǐng)求上。因此,改善響應(yīng)時(shí)間最簡(jiǎn)單的辦法就是減少組件數(shù)量并由此減少HTTP請(qǐng)求數(shù)。減少組件數(shù)量通常會(huì)和產(chǎn)品設(shè)計(jì)的初衷相矛盾,因此,此處給出了一些技術(shù):
圖片地圖(Image Maps)聯(lián)合多個(gè)圖片到一個(gè)單獨(dú)的圖片中。下載圖片大小的總和保持不變,但是,通過減少HTTP請(qǐng)求數(shù)的方式加速了頁面。圖片地圖適用于導(dǎo)航欄或其他超鏈接中使用多個(gè)圖片的情形。但是,在定義圖片地圖上的區(qū)域坐標(biāo)時(shí),如果采用手工方式很難完成且容易出錯(cuò),而且除了矩形外幾乎無法定義其他形狀。
CSS Sprites使用CSS background-image和background-position屬性將多個(gè)圖片聯(lián)合成一個(gè)獨(dú)立的圖片來顯示。它通過合并圖片減少了HTTP請(qǐng)求,并且比圖片地圖更加靈活,同時(shí)也降低了圖片的下載量。如果在頁面中需要為背景、按鈕、導(dǎo)航欄、鏈接等提供大量圖片,CSS Sprites是一種優(yōu)秀的解決方案。
內(nèi)聯(lián)圖片(Inline images)使用data: URL scheme模式將圖片嵌入到HTML文檔中。通過此模式嵌入圖片,不需要任何額外的HTTP請(qǐng)求開銷。但是,目前的主流瀏覽器(主要是IE)不支持此種方式。
合并文件(Combined files)通過將所有JavaScript腳本合并到一個(gè)文件,所有CSS樣式表合并到另一個(gè)文件的方式來減少HTTP請(qǐng)求的數(shù)量。但是簡(jiǎn)單的合并通常會(huì)遇到模塊化、頁面變化等問題,需要根據(jù)頁面引用腳本和樣式表來具體分析以確定具體的組合方式。
規(guī)則2——使用內(nèi)容發(fā)布網(wǎng)絡(luò)(Use a Content Delivery Network)
用戶同Web服務(wù)器的距離會(huì)對(duì)頁面響應(yīng)時(shí)間產(chǎn)生影響。網(wǎng)站最初通常將其所有服務(wù)器放在同一個(gè)地方,當(dāng)用戶群增加時(shí),公司必須面對(duì)服務(wù)器放置地點(diǎn)不再合適的事實(shí)。因此,有必要在多個(gè)地理位置不同的服務(wù)器上部署內(nèi)容。
作為實(shí)現(xiàn)地理位置分離的第一步,不應(yīng)當(dāng)首先嘗試使用分布式架構(gòu)重新設(shè)計(jì)Web應(yīng)用程序。這樣的應(yīng)用程序決定了重新設(shè)計(jì)將帶來如同步會(huì)話狀態(tài)、在服務(wù)器放置地點(diǎn)間復(fù)制數(shù)據(jù)庫事務(wù)等復(fù)雜問題。重新設(shè)計(jì)會(huì)推遲甚至根本無法實(shí)現(xiàn)縮短用戶和網(wǎng)站內(nèi)容距離的愿望。
如果應(yīng)用程序Web服務(wù)器里用戶更近,則一個(gè)HTTP請(qǐng)求的響應(yīng)時(shí)間將被縮短;如果組件Web服務(wù)器離用戶更近,則多個(gè)HTTP請(qǐng)求的響應(yīng)時(shí)間將縮短。因此,與其重新開始設(shè)計(jì)應(yīng)用程序,以便將應(yīng)用程序Web服務(wù)器分散開,不如首先將組件Web服務(wù)器分散開。這不僅能達(dá)到響應(yīng)時(shí)間大幅減少的目的,還很容易實(shí)現(xiàn)。
內(nèi)容發(fā)布網(wǎng)絡(luò)(CDN)是一組分布在多個(gè)不同地理位置的Web服務(wù)器,用于更加有效的向用戶發(fā)布內(nèi)容。向特定用戶發(fā)布內(nèi)容的服務(wù)器基于對(duì)網(wǎng)絡(luò)可用度的測(cè)量,例如,CDN可能選擇網(wǎng)絡(luò)階躍數(shù)最小的服務(wù)器,或者具有最短響應(yīng)時(shí)間的服務(wù)器。
除了縮短響應(yīng)時(shí)間外,CDN還可以帶來其他優(yōu)勢(shì),包括備份、擴(kuò)展存儲(chǔ)能力和進(jìn)行緩存;同時(shí),CDN還有助于緩和Web流量峰值的壓力,如在獲取天氣或股市新聞、瀏覽體育或娛樂事件時(shí)。依賴CDN的一個(gè)缺點(diǎn)是網(wǎng)站的響應(yīng)時(shí)間會(huì)受到其他網(wǎng)站——甚至可能是競(jìng)爭(zhēng)對(duì)手流量的影響;另一個(gè)缺點(diǎn)是無法直接控制組件服務(wù)器所帶來的問題。
CDN用于發(fā)布靜態(tài)內(nèi)容(如圖片、腳本、樣式表、Flash)。提供動(dòng)態(tài)HTML頁面會(huì)引入特殊的存儲(chǔ)要求——數(shù)據(jù)庫連接、狀態(tài)管理、驗(yàn)證、硬件和OS優(yōu)化等,這些復(fù)雜性超過了CDN的范圍。另一方面,靜態(tài)文件更容易存儲(chǔ)并具有較少的依賴。
規(guī)則3——添加Expires頭(Add an Expires or a Cache-Control Header)
Web頁面包含大量組件,并且數(shù)量在不斷增長(zhǎng)。頁面的初訪者會(huì)進(jìn)行很多的HTTP請(qǐng)求,但通過一個(gè)長(zhǎng)久的Expires頭,可以使這些組件被緩存下來,可以在后續(xù)的頁面瀏覽中避免不必要的HTTP請(qǐng)求。長(zhǎng)久的Expires頭最長(zhǎng)用于圖片,但應(yīng)該將其用于所有組件上,包括腳本、樣式表和Flash。
Web服務(wù)器使用Expires頭告訴Web客戶端它可以使用一個(gè)組件的當(dāng)前副本,知道指定時(shí)間為止。HTTP規(guī)范中簡(jiǎn)要的稱該頭為“在這一日期/時(shí)間之后,響應(yīng)將被認(rèn)為是無效的”。例如:
Expires: Thu, 15 Apr 2010 20:00:00 GMT
告訴瀏覽器該響應(yīng)的有效性持續(xù)到2010年4月15日。
因?yàn)镋xpires頭使用一個(gè)特定的時(shí)間,它要求服務(wù)端和客戶端的時(shí)鐘嚴(yán)格同步;另外,過期日期需要經(jīng)常檢查,一旦過期日期到了,需要在服務(wù)器中配置提供一個(gè)新的日期。所以,HTTP1.1引入了Cache-Control頭來克服Exipres頭的限制。Cache-Control使用max-age指令指定組件被緩存多久,它以秒為單位定義了一個(gè)更新窗。使用帶有max-age的Cache-Control可以消除Expires的限制,但對(duì)于不支持HTTP1.1的應(yīng)用,仍希望使用Expires頭??梢酝瑫r(shí)制定這兩個(gè)響應(yīng)頭,如果兩者同時(shí)出現(xiàn)時(shí),HTTP規(guī)范規(guī)定max-age指令將重寫Expires頭。
當(dāng)出現(xiàn)了Expires頭時(shí),直到過期時(shí)間為止一直會(huì)使用緩存的版本,瀏覽器不會(huì)檢查任何更新,直到過了過期時(shí)間。為了確保用戶能夠獲取組件的最新版本,需要在所有的HTML頁面中修改組件的文件名。Yahoo在此使用了將版本號(hào)嵌入在組件的文件名中的方法。
規(guī)則4——壓縮組件(Gzip Components)
壓縮組件通過減少HTTP請(qǐng)求產(chǎn)生的響應(yīng)包的大小,從而降低傳輸時(shí)間的方式來提高性能。從HTTP1.1開始,Web客戶端可以通過HTTP請(qǐng)求中的Accept-Encoding頭來標(biāo)識(shí)對(duì)壓縮的支持:
Accept-Encoding: gzip, deflate
如果Web服務(wù)器看到請(qǐng)求中的這個(gè)頭,就會(huì)使用客戶端列出的方法中的一種來壓縮響應(yīng)。Web服務(wù)器通過響應(yīng)中的Content-Encoding頭來通知Web客戶端:
Content-Encoding: gzip
目前許多網(wǎng)站通常會(huì)壓縮HTML文檔,腳本和樣式表的壓縮也是值得的(包括XML和JSON在內(nèi)的任何文本響應(yīng)理論上都值得被壓縮)。但是,圖片和PDF文件不應(yīng)該被壓縮,因?yàn)樗鼈儽緛硪呀?jīng)被壓縮了。
壓縮通常能將響應(yīng)的數(shù)據(jù)量減少近70%,但是壓縮通常情況下會(huì)帶來服務(wù)端和客戶端的CPU開銷,要檢測(cè)受益是否大于開銷,需要綜合考慮響應(yīng)大小、連接的帶寬和客戶端也服務(wù)端直接的距離等因素。通常需要對(duì)大于1KB或2KB的文件進(jìn)行壓縮。
當(dāng)瀏覽器通過代理來發(fā)送請(qǐng)求時(shí),有可能出現(xiàn)瀏覽器期望接受的壓縮后內(nèi)容和實(shí)際接收到的不一致的情況。解決這一問題的方法是在Web服務(wù)器的響應(yīng)中添加Vary頭。Web服務(wù)器可以告訴代理根據(jù)一個(gè)或多個(gè)請(qǐng)求頭來改變緩存的響應(yīng)。由于壓縮的決定是基于Accept-Encoding請(qǐng)求頭的,因此需要在服務(wù)器的Vary響應(yīng)頭中包含Accept-Encoding:
Vary: Accept-Encoding
目前大約90%的通過瀏覽器進(jìn)行的Internet通信都需要使用gzip,使得服務(wù)端和客戶端的對(duì)等性變得額外重要。無論是客戶端還是服務(wù)端發(fā)送錯(cuò)誤,都會(huì)造成頁面被破壞。避免錯(cuò)誤的一種方式是采用“瀏覽器白名單”方式,即只為經(jīng)過證實(shí)支持壓縮的瀏覽器提供壓縮內(nèi)容,但是當(dāng)代理緩存加進(jìn)來以后,處理邊緣情形瀏覽器將變得更加復(fù)雜。另一種方式是使用Vary: *或Cache-Control: private頭來禁用代理緩存。此種方式會(huì)為所有瀏覽器禁用代理緩存,從而增加帶寬開銷。如何平衡壓縮和代理支持需要在加快響應(yīng)時(shí)間、減小帶寬開銷和邊緣情形瀏覽器缺陷之間進(jìn)行權(quán)衡:
如果網(wǎng)站的用戶很少,并且他們處于一個(gè)小圈子中,邊緣情形瀏覽器不需要太多關(guān)注,可以壓縮內(nèi)容并使用Vary: Accept-Encoding。
如果更注重帶寬開銷,可以和前一種情形一樣,壓縮內(nèi)容并使用Vary: Accept-Encoding。
如果網(wǎng)站擁有大量的、多變的用戶群,能夠應(yīng)付較高的帶寬開銷,并且享有高質(zhì)量的名聲,需要壓縮內(nèi)容并使用Cache-Control: Private。(Google和Yahoo都使用這種方式)
規(guī)則5——將樣式表放在頂部(Put Stylesheets at the Top)
我們都希望頁面能夠逐步加載,也就是說,我們希望瀏覽器能夠盡快顯示內(nèi)容。當(dāng)瀏覽器逐步加載頁面時(shí),頁頭、導(dǎo)航欄、頂端logo等所有這些都會(huì)等待頁面的用戶提供視覺反饋,這改善了用戶體驗(yàn)。將樣式表放在底部,為避免當(dāng)樣式變化時(shí)重繪頁面中的元素,瀏覽器會(huì)阻塞內(nèi)容逐步呈現(xiàn)。
樣式表在頁面中的位置并不影響下載時(shí)間,但是會(huì)影響頁面的呈現(xiàn)。根據(jù)HTML規(guī)范“和A不一樣,[LINK]只能出現(xiàn)在文檔的HEAD節(jié)中,但其出現(xiàn)次數(shù)是任意的”。因此,問題的解決方式應(yīng)該是遵循HTML規(guī)范,使用LINK標(biāo)簽將樣式表放在文檔的HEAD中。
規(guī)則6——將腳本放在底部(Put Scripts at the Bottom)
對(duì)響應(yīng)時(shí)間影響最大的是頁面中的組件數(shù)量,而腳本會(huì)阻塞組件的并行下載,帶來性能上的問題。HTTP1.1規(guī)范建議瀏覽器從每個(gè)主機(jī)名并行下載兩個(gè)組件。如果一個(gè)Web頁面平均將其組件分別放在兩個(gè)主機(jī)名下,整體響應(yīng)時(shí)間可以減少大約一半。我們可以通過對(duì)瀏覽器默認(rèn)設(shè)置的修改來增加每個(gè)主機(jī)名并行下載組件的數(shù)量,也可以使用CNAME(DNS別名)將組件分別放到多個(gè)主機(jī)名下。但是,增加并行下載數(shù)量通常會(huì)帶來性能上的開銷,過多的并行下載有時(shí)反而會(huì)降低性能。Yahoo!研究表明,使用兩個(gè)主機(jī)名比使用1、4或10個(gè)主機(jī)名能帶來更好的性能。
需要我們注意的是,下載腳本時(shí)并行下載實(shí)際上是被禁用的,即使此時(shí)使用了不同的主機(jī)名,瀏覽器也不會(huì)啟動(dòng)其他下載。因此,如果將腳本放在頂部,腳本會(huì)阻塞后面內(nèi)容的呈現(xiàn),也會(huì)阻塞后面組件的下載。因此,放置腳本最好的地方是頁面底部,這不會(huì)阻止頁面內(nèi)容呈現(xiàn),而且頁面中的可視組件可以盡早下載。
規(guī)則7——避免CSS表達(dá)式(Avoid CSS Expressions)
CSS表達(dá)式是動(dòng)態(tài)設(shè)置CSS屬性的一種強(qiáng)大(并且危險(xiǎn))的方式。它從IE5以后的版本被支持,在IE8中已經(jīng)被廢棄。
表達(dá)式的問題在于對(duì)其進(jìn)行的求值頻率比人們期望的要高。它們不只在呈現(xiàn)頁面和大小改變時(shí)求值,當(dāng)頁面滾動(dòng),甚至用戶鼠標(biāo)在頁面上移過時(shí)都要進(jìn)行求值。
減少CSS表達(dá)式求值次數(shù)的一種方式是使用一次性表達(dá)式,如果CSS表達(dá)式必須被求值一次,可以在這一次中執(zhí)行重寫它本身。除此之外,還可以使用事件處理器來為特定的事件提供所期望的動(dòng)態(tài)行為。
規(guī)則8——使用外部JavaScript和CSS(Make JavaScript and CSS External)
在現(xiàn)實(shí)環(huán)境中使用外部文件通常會(huì)產(chǎn)生較快的頁面,因?yàn)镴avaScript和CSS有機(jī)會(huì)被瀏覽器緩存起來。對(duì)于內(nèi)聯(lián)的情況,由于HTML文檔通常不會(huì)被配置為可以進(jìn)行緩存的,所以每次請(qǐng)求HTML文檔都要下載JavaScript和CSS。所以,如果JavaScript和CSS在外部文件中,瀏覽器可以緩存它們,HTML文檔的大小會(huì)被減少而不必增加HTTP請(qǐng)求數(shù)量。
決定是否使用外部文件的關(guān)鍵在于被緩存的外部文件占請(qǐng)求的HTML文檔數(shù)的比重。如果網(wǎng)站用戶在每次會(huì)話中進(jìn)行多次頁面訪問,同時(shí)頁面重用了多個(gè)腳本和樣式表,使用外部文件時(shí)很好的選擇。
對(duì)于大多數(shù)網(wǎng)站而言,難以精確度量以判斷是否使用內(nèi)聯(lián)或外部文件,此時(shí)建議是使用外部文件的方式。對(duì)于這個(gè)問題的一個(gè)例外是網(wǎng)站主頁,由于主頁對(duì)于響應(yīng)時(shí)間要求更高,因此更加傾向于內(nèi)聯(lián)而不是外部文件。
對(duì)于內(nèi)聯(lián)文件而言,由于無法利用瀏覽器緩存,因此給人感覺依然比較低效。我們可以通過加載后下載和動(dòng)態(tài)內(nèi)聯(lián)的方式來使得網(wǎng)站主頁既可以獲得內(nèi)聯(lián)的優(yōu)勢(shì),同時(shí)也能緩存外部文件。
規(guī)則9——減少DNS查找(Reduce DNS Lookups)
DNS對(duì)于網(wǎng)站來說會(huì)帶來開銷。通常瀏覽器查找一個(gè)給定主機(jī)名的IP要花費(fèi)20~120毫秒的時(shí)間。在DNS查找完成之前,瀏覽器不能從此主機(jī)下載任何東西。
DNS查找可以被緩存起來以提高性能,這種緩存可以發(fā)生在ISP或局域網(wǎng)中的一臺(tái)特殊的緩存服務(wù)器上,同時(shí),緩存也會(huì)發(fā)生在獨(dú)立的用戶機(jī)器上。在用戶請(qǐng)求一個(gè)主機(jī)名后,DNS信息會(huì)留在操作系統(tǒng)的DNS緩存中,大多數(shù)瀏覽器也擁有自己的緩存,和操作系統(tǒng)緩存相分離。只要瀏覽器在其緩存中保留了DNS記錄,就不會(huì)通過操作系統(tǒng)來請(qǐng)求這個(gè)記錄。
當(dāng)客戶端瀏覽器和操作系統(tǒng)中DNS緩存同時(shí)為空時(shí),DNS查詢的數(shù)量等于頁面中唯一主機(jī)名的數(shù)量,這些主機(jī)名包括了頁面的URL、圖片、腳本、樣式表、Flash等。所以,減少唯一主機(jī)名數(shù)量,可以減少DNS查詢數(shù)。
減少唯一主機(jī)名數(shù)量會(huì)潛在的減少頁面中并行下載的數(shù)量。避免DNS查找降低了響應(yīng)時(shí)間,但減少并行下載可能會(huì)增加響應(yīng)時(shí)間。對(duì)于這種情形,建議將這些組件放在至少2個(gè),但不要超過4個(gè)主機(jī)名下。
規(guī)則10——精簡(jiǎn)JavaScript和CSS(Minify JavaScript and CSS)
精簡(jiǎn)是從代碼中移除不必要的字符以減小其大小,進(jìn)而改善加載時(shí)間。在代碼被精簡(jiǎn)后,所有注釋以及不必要的空白字符(空格、換行和制表符)都將被移除。對(duì)于JavaScript而言,因?yàn)樾枰螺d的文件大小減小了,可以改善響應(yīng)時(shí)間。
混淆是可以應(yīng)用在源代碼上的另一種優(yōu)化方式。相比較于精簡(jiǎn),混淆更加復(fù)雜,因此更容易產(chǎn)生bug?;煜梢愿蟪潭壬蠅嚎s源代碼,但是也存在著一定的風(fēng)險(xiǎn)。
除了外部JavaScript外,內(nèi)聯(lián)在<script>和<style>塊中的源代碼也需要被精簡(jiǎn)。即使使用了gzip來壓縮JavaScript和CSS,使用精簡(jiǎn)能夠?qū)⒋a大小再減少5%或者更多。
規(guī)則11——避免重定向(Avoid Redirects)
重定向用于將用戶從一個(gè)URL路由到另一個(gè)URL。重定向有很多種,其中301和302是最常用的兩種。下面是一個(gè)301響應(yīng)頭的示例:
HTTP/1.1 301 Moved Permanently
Location: http://example.com/newuri
Content-Type: text/html
瀏覽器會(huì)自動(dòng)將用戶帶到Location字段給出的URL。重定向所必需的所有信息都包含在這個(gè)頭中,響應(yīng)體通常是空的。不管叫什么名字,301或者302響應(yīng)在實(shí)際中都不會(huì)被緩存,除非有附加的頭(如Expires或Cache-Control等)要求它這么做。meta refresh標(biāo)簽和JavaScript也可以用于重定向,但是最好的技術(shù)是使用標(biāo)準(zhǔn)的3xx狀態(tài)碼,以保證后退按鈕能夠正常工作。
需要我們記住的是重定向會(huì)使頁面變慢。在用戶和HTML文檔間插入一個(gè)重定向后,在此HTML文檔到達(dá)之前頁面上不會(huì)描繪任何東西,任何組件也不會(huì)被下載。
有一種重定向最為浪費(fèi),發(fā)生的也很頻繁,但是Web開發(fā)人員通常都沒有意識(shí)到它,它發(fā)生在URL的結(jié)尾必須出現(xiàn)斜線(/)而沒有出現(xiàn)的情形。例如訪問地址http://astrology.yahoo.com/astrology將導(dǎo)致一個(gè)301響應(yīng)包含重定向至http://astrology.yahoo.com/astrology/。當(dāng)主機(jī)名后缺少結(jié)尾斜線時(shí)不會(huì)發(fā)生重定向。在Apache中,我們可以通過Alias指令或者mod_rewrite模塊或者DirectorySlash指令來處理缺少結(jié)尾斜線時(shí)的重定向問題。
從一個(gè)舊的站點(diǎn)鏈接到新的站點(diǎn)是使用重定向的另一種常見場(chǎng)景。其他形式還包括將一個(gè)網(wǎng)站的不同部分連接起來,以及基于一些條件(瀏覽器類型、用戶帳戶類型等)來引導(dǎo)用戶。使用重定向來連接兩個(gè)網(wǎng)站很簡(jiǎn)單而且只需要很少的額外代碼。但是,雖然重定向降低了開發(fā)的復(fù)雜性,也損害了用戶體驗(yàn),通常可以進(jìn)行其他的選擇:如果兩個(gè)代碼的路徑在同一臺(tái)服務(wù)器上,可以使用Alias和mod_rewrite;如果域名由于重定向發(fā)生改變,可以使用一個(gè)CNAME(一條DNS記錄,用于創(chuàng)建一個(gè)域名指向另一個(gè)域名的別名)讓兩個(gè)主機(jī)名指向相同的服務(wù)器,然后使用Alias和mod_rewrite。
規(guī)則12——移除重復(fù)腳本(Remove Duplicate Scripts)
在一個(gè)頁面中兩次保護(hù)同一個(gè)JavaScript文件會(huì)損傷性能。導(dǎo)致一個(gè)腳本重復(fù)的因素主要有兩個(gè)——團(tuán)隊(duì)大小和腳本數(shù)量。
當(dāng)重復(fù)腳本的現(xiàn)象發(fā)生時(shí),將產(chǎn)生不必要的HTTP請(qǐng)求和浪費(fèi)執(zhí)行JavaScript的時(shí)間。不必要的HTTP請(qǐng)求會(huì)發(fā)生在IE中,而不會(huì)發(fā)生在Firefox中。在IE中,如果腳本被包含兩次且沒有被緩存,瀏覽器會(huì)在頁面加載期間產(chǎn)生兩個(gè)HTTP請(qǐng)求;即使腳本可以緩存,當(dāng)用戶重新加載頁面時(shí)也會(huì)產(chǎn)生額外的HTTP請(qǐng)求。對(duì)JavaScript進(jìn)行的多余的執(zhí)行從而浪費(fèi)時(shí)間的現(xiàn)象在IE和Firefox中都存在,與腳本是否被緩存無關(guān)。
避免意外包含同一腳本兩次的一種方法是在你的模塊系統(tǒng)中實(shí)現(xiàn)一個(gè)腳本管理模塊。包含腳本的典型方式是在HTML頁面中使用SCRIPT標(biāo)簽:
- <script type=”text/javascript” src=”menu_1.0.17.js”></script>
另一種選擇是在PHP中創(chuàng)建一個(gè)函數(shù):
- <?php insertScript(“menu.js”) ?>
為了防止統(tǒng)一個(gè)腳本被重復(fù)添加多次,insertScript函數(shù)需要添加處理腳本的依賴性和版本的功能。
規(guī)則13——配置Etag(Configure ETags)
實(shí)體標(biāo)簽(Entity Tag,ETag)是Web服務(wù)器和瀏覽器用于確認(rèn)緩存組件的有效性的一種機(jī)制。ETag在HTTP1.1中引入,用于檢測(cè)瀏覽器緩存中的組件與原始服務(wù)器上的組件是否匹配。ETag是唯一標(biāo)識(shí)了一個(gè)組件的一個(gè)特定版本字符串。唯一的約束是該字符串必須用引號(hào)引起來。原始服務(wù)器使用Etag響應(yīng)頭來指定組件的ETag。
HTTP/1.1 200 OK
Last-Modified: Tue, 12 Dec 2006 03:03:59 GMT
ETag: “10c24bc-4ab-457e1c1f”
Content-Length: 12195
此后,如果瀏覽器必須驗(yàn)證一個(gè)組件,它會(huì)使用If-None-Match頭將ETag傳回原始服務(wù)器。如果ETag是匹配的,就會(huì)返回304狀態(tài)碼,在此例中使響應(yīng)減少12195字節(jié)。
GET /i/yahoo.gif HTTP/1.1
Host: us.yimg.com
f-Modified-Since: Tue, 12 Dec 2006 03:03:59 GMT
If-None-Match: “10c24bc-4ab-457e1c1f”
HTTP/1.1 304 Not Modified
ETag的問題在于,通常使用組件的某些屬性來構(gòu)造它,這些屬性對(duì)于特定的、寄宿了網(wǎng)站的服務(wù)器來說是唯一的。當(dāng)瀏覽器從一臺(tái)服務(wù)器上獲取了原始組件之后又嘗試向另一臺(tái)服務(wù)器來驗(yàn)證組件時(shí),ETag是不匹配的。這種情況對(duì)于使用服務(wù)器集群來處理請(qǐng)求的網(wǎng)站來說是很常見的一種情況。默認(rèn)情況下,Apache和IIS向ETag中嵌入的數(shù)據(jù)都會(huì)大大降低有效性驗(yàn)證的成功率。
Apache1.3和2.x的ETag格式是inode-size-timestamp。文件系統(tǒng)使用inode來存儲(chǔ)諸如文件類型、所有者、組和訪問模式等信息。盡管在多臺(tái)服務(wù)器上一個(gè)給定的文件可能位于相同的目錄、具有相同的文件大小、權(quán)限、時(shí)間戳等,從一臺(tái)服務(wù)器到另一臺(tái)服務(wù)器,器inode仍然是不同的。
IIS5.0和6.0在ETag上有著類似的問題。IIS上ETag的格式是Filetimestamp:ChangeNumber。ChangeNumber適用于跟蹤IIS配置變化的計(jì)數(shù)器。對(duì)于一個(gè)網(wǎng)站背后的所有IIS服務(wù)器來說,ChangeNumber不大可能相同。
最
終的結(jié)果是,對(duì)于完全相同的組件,從一臺(tái)服務(wù)器到另一臺(tái),Apache和IIS產(chǎn)生的ETag是不會(huì)匹配的。如果ETag不匹配,用戶就不會(huì)按照ETag的設(shè)計(jì)計(jì)劃那樣接收到更小更快的304響應(yīng);相反,它們會(huì)收到普通的200響應(yīng)以及組件的所有數(shù)據(jù)。如果只在一臺(tái)服務(wù)器上部署網(wǎng)站,這通常不會(huì)產(chǎn)生問題;但如果使用了服務(wù)器集群,同時(shí)使用Apache或者IIS進(jìn)行默認(rèn)的ETag配置,用戶響應(yīng)將變慢,服務(wù)器負(fù)載將變高,將消耗更多的帶寬,同時(shí)代理緩存的效率也會(huì)下降。即使組件具有長(zhǎng)久的Expires頭,一旦用戶單擊了Reload或Refresh按鈕,依然會(huì)產(chǎn)生條件GET請(qǐng)求。
如果組件必須通過最新修改日期之外的一些東西來進(jìn)行驗(yàn)證,則ETag是一種強(qiáng)大的方法;如果無須自定義ETag,則最好將其移除。Last-Modified頭基于組件的時(shí)間戳進(jìn)行驗(yàn)證,可以提供完全等價(jià)的信息,而且移除ETag可以減少響應(yīng)和后續(xù)請(qǐng)求的HTTP頭的大小。在Apache中,只要向Apache配置文件中簡(jiǎn)單地添加下面一行配置就能移除ETag:
FileETag none
規(guī)則14——使Ajax可緩存(Make Ajax Cacheable)
Ajax的一個(gè)最重要的優(yōu)點(diǎn)就是向用戶提供即時(shí)反饋,因?yàn)樗惒降膹暮笈_(tái)Web服務(wù)器請(qǐng)求信息。但是,使用Ajax并不保證用戶不會(huì)等到異步的JavaScript和XML返回響應(yīng)。在很多應(yīng)用程序中,用戶是否需要等待取決于如何使用Ajax。用戶是否需要等待的關(guān)鍵因素在于Ajax請(qǐng)求是主動(dòng)的還是被動(dòng)的。主動(dòng)請(qǐng)求是基于用戶的當(dāng)前操作而發(fā)起的,被動(dòng)請(qǐng)求則是為了將來使用而預(yù)先發(fā)起的。我們需要注意的是,“異步”并沒有暗示“實(shí)時(shí)”。
為了提升性能,最重要的是優(yōu)化Ajax響應(yīng)。而改善這些主動(dòng)Ajax請(qǐng)求的最重要的方式就是使響應(yīng)可緩存。如同在“添加Expires頭”中討論的,一些其他規(guī)則也適用于Ajax,包括:壓縮組件、減少DNS查找、精簡(jiǎn)JavaScript、避免重定向、配置Etag。
PS:具體的關(guān)于優(yōu)化的知識(shí)點(diǎn)或問題
1. 為什么網(wǎng)頁設(shè)置緩存后仍然有請(qǐng)求(304響應(yīng))?
瀏覽器刷新是conditional request,所以如果通過刷新來看緩存是否有效肯定是304??梢栽囋囕斎刖W(wǎng)址按回車或者回退鍵來看效果。另外由于HTML文檔很少設(shè)置完全緩存(一般要和服務(wù)器驗(yàn)證),可以看靜態(tài)組件的緩存效果(200 ok (from cache))。
2. expirationTime = responseTime + freshnessLifetime - currentAge
freshnessLifetime具體怎么算可以參考https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching_FAQ。
3. Flash of unstyled content(無樣式內(nèi)容閃爍)
Flash of unstyled content(FOUC)就是在加載外部樣式表之前,瀏覽器按默認(rèn)樣式顯示了內(nèi)容,這是因?yàn)闉g覽器在所有資源都下載好前就開始渲染頁面了。一旦外部樣式被加載,瀏覽器就會(huì)修正樣式,但這種修正可能是可見的,也就是FOUC。
怎么避免?在<head>中通過<link>引入樣式,避免使用@import。
相關(guān)文章
以淘寶前端為例剖析HTML5與移動(dòng)端頁面的性能優(yōu)化
這篇文章主要介紹了以淘寶前端為例剖析HTML5與移動(dòng)端頁面的性能優(yōu)化,作者談到了移動(dòng)端瀏覽器與PC桌面的性能差距所導(dǎo)致的HTML5體驗(yàn)相異,以及CSS3動(dòng)畫等的使用問題,需要的朋2016-04-26- 這篇文章主要介紹了Web前端針對(duì)圖片顯示的優(yōu)化方案,談到了一些圖片格式的優(yōu)缺點(diǎn)以及圖片壓縮等常用手段的技巧分析,列舉了包括Medium和Facebook等多家巨頭所采用的方案,需要2016-04-26
dns-prefetch是什么 前端優(yōu)化:DNS預(yù)解析提升頁面速度
在網(wǎng)頁體驗(yàn)中我們常會(huì)遇到這種情況,即在調(diào)用百度聯(lián)盟、谷歌聯(lián)盟以及當(dāng)前網(wǎng)頁所在域名外的域名文件時(shí)會(huì)遇到請(qǐng)求延時(shí)非常嚴(yán)重的情況。那么有沒有方法去解決這種請(qǐng)求嚴(yán)重延時(shí)2021-08-07web前端性能優(yōu)化之合理的優(yōu)化網(wǎng)站圖片可以帶來更多的流量
無論什么網(wǎng)站都少不了圖片,據(jù)統(tǒng)計(jì),60%的網(wǎng)站流量均來自網(wǎng)站圖畫,可見網(wǎng)站的圖片對(duì)網(wǎng)站流量的影響,但是該怎么優(yōu)化圖片呢?下面分享web前端圖畫極限優(yōu)化策略,需要的朋友2016-01-08SEO圖片優(yōu)化:web前端圖片極限優(yōu)化策略
隨著web發(fā)展,網(wǎng)站資源的流量也變得越來越大,而據(jù)統(tǒng)計(jì),60%的網(wǎng)站流量均來自網(wǎng)站圖片,可見對(duì)圖片合理優(yōu)化可以大幅影響網(wǎng)站流量,減小帶寬消耗和服務(wù)器壓力,本文將提供we2016-01-07- 這篇文章主要介紹了一張圖看懂移動(dòng)HTML5前端性能優(yōu)化的相關(guān)資料,需要的朋友可以參考下2015-11-02
SEO網(wǎng)站優(yōu)化中URL優(yōu)化在前端設(shè)計(jì)中的重要作用
網(wǎng)站在SEO中URL優(yōu)化十分重要,那怎么做呢?在前端設(shè)計(jì)中也要引起重視,看看該文是如何闡述的,希望可以幫助到有需要的朋友2014-01-13web前端優(yōu)化時(shí)為什么不建議使用css @import
研究web前端優(yōu)化時(shí)最多的建議就是不要使用 css @import 因?yàn)橛眠@種方式加載css相當(dāng)于把css放在了html底部,關(guān)于這一點(diǎn)下面為大家詳細(xì)介紹下2013-12-27- 上篇文章的留言里有好多朋友是對(duì)我css架構(gòu)就http請(qǐng)求的問題提出質(zhì)疑,我本想回答的,但不知道從何說起.希望這里面的東西有你想要的答案吧,感興趣的朋友可以了解下吧2013-01-13
了解html頁面的渲染過程以備學(xué)習(xí)前端的性能優(yōu)化(續(xù))
上一篇關(guān)于瀏覽器的渲染過程只是通過一小段代碼解釋了一下,并沒有通過瀏覽器測(cè)試,說服力不夠,而且還有很多不完善的地方,今天在瀏覽器中測(cè)試了一下,并把測(cè)試的結(jié)果分享2013-01-13