本文大部份內容翻譯自雅虎前端的性能優化,如何讓頁面加載更快,雅虎給出了多個規則,原文地址:Best Practices for Speeding Up Your Web Site 。主要從八個方向分別介紹瞭如何進行性能的優化。php
雅虎軍規上說明80%的響應時間都來自前端,大多數頁面的加載時間都是在下載圖片,樣式,js,flash等,減小組件的數量反過來減小請求的數量是頁面加載更快的關鍵。css
減小頁面組件數量的一種方法是簡化頁面設計,可是如何在構建更豐富內容的基礎上,同時還能減小相應時間?html
JavaScript
,CSS
文件來減小HTTP請求的數量來縮短響應時間。background-image
和background-position
屬性來顯示部分須要的圖像。data:url scheme
將圖像嵌入實際頁面中。DNS就像電話簿將人們的姓名映射到他們的電話號碼同樣,當您輸入www.yahoo.com
時,瀏覽器會經過DNS解析返回服務器的IP地址,這個DNS解析過程須要成本,一般須要20-120ms才能解析成功,在這以前,瀏覽器沒法從服務器獲取任何內容。前端
經過緩存DNS查找來得到更好的性能。DNS信息保留在操做系統的DNS緩存中,大多數的瀏覽器都有本身的緩存,與操做系統的分開。express
默認狀況,IE會將DNS查找緩存30分鐘,FireFox緩存一分鐘。json
當客戶端的DNS緩存爲空(對於瀏覽器和操做系統)時,DNS查找的數量等於網頁中惟一主機名的數量。 減小惟一主機名的數量可減小DNS查找的數量。後端
減小惟一主機名的數量有可能減小頁面中發生的並行下載量。避免DNS查找會縮短響應時間,但減小並行下載可能會縮短響應時間。 準則是將這些組件分紅至少兩個但不超過四個主機名。這是減小DNS查找和容許高度並行下載之間的良好折衷。跨域
使用301和302狀態碼完成重定向。下面是一個301響應http頭示例:瀏覽器
HTTP/1.1 301 Moved Permanently Location: http://example.com/newuri Content-Type: text/html
瀏覽器自動將用戶帶到Location
字段指定的URL。跳轉所需的全部信息都在http頭 ,響應的主體一般是空的。301或302響應通常不會被緩存,除非有Expires
或者Cache-Control
指定要緩存。緩存
要記住的主要事情是重定向會下降用戶體驗。在用戶和HTML文檔之間插入重定向會延遲頁面中的全部內容,由於頁面中的任何內容都沒法呈現,而且在HTML文檔到達以前不會開始下載任何組件。
最浪費的重定向之一常常發生,就是在URL中缺乏尾部/
會產生301響應,好比http://astrology.yahoo.com/astrology
會301
跳轉到http://astrology.yahoo.com/astrology/
。
使Ajax可緩存的好處之一就是在用戶請求時能夠提供快速反饋,由於它從後端Web服務器異步請求信息。重要的是要記住「異步」並不意味着「瞬時」。
爲了提升性能,優化這些Ajax響應很是重要。提升Ajax性能的最重要方法是使響應可緩存,其中提升的方法除了Add an Expires or a Cache-Control Header 中討論的以外,其餘方法還有:
你能夠自習看看你的頁面並問問你本身,最初頁面的渲染須要什麼,其餘的內容和組件就是能夠延遲加載的。
JavaScript
是在 onload
時間以前和以後拆分的理想候選者,例如,若是您有拖放和動畫的JS代碼,則能夠延遲加載,由於它須要在頁面渲染完以後才能夠執行。其它可延遲的包括隱藏的內容,摺疊起來的圖片等等。
預加載看起來和延遲加載相反,但它實際上有着不一樣的目標,經過預加載組件,您能夠利用瀏覽器空閒的時間並請求未來須要的組件(如圖像,樣式和腳本)。這樣,當用戶訪問下一頁時,您能夠將大部分組件放在緩存中,而且用戶加載頁面將更快。
有幾種預加載類型:
onload
觸發,你當即獲取另外的組件。好比谷歌會在主頁這樣加載搜索結果頁面用到的雪碧圖。複雜頁面意味着要下載更多字節,這也意味着JavaScript中的DOM訪問速度更慢。例如,當您想要添加事件處理程序時,若是在頁面上循環遍歷500或5000個DOM元素,則會有所不一樣。
拆分組件來達到最大化的並行下載,因爲DNS查詢的反作用,最好保證使用的域名不許超過2-4個。例如,您能夠託管HTML和動態內容,www.example.org
並在static1.example.org
和之間拆分靜態組件。
iframe容許html文檔被插入到父文檔。
<iframe>
優勢:
<iframe>
缺點:
onload
HTTP的請求是很是昂貴的,所以發出的HTTP請求得到無用的響應是徹底沒有必要的,而且會影響用戶體驗。
一些網站會有特別的404頁面提升用戶體驗,但這仍然會浪費服務器資源。特別壞的是當連接指向外部js但卻獲得404結果。這樣首先會下降(佔用)並行下載數,其次瀏覽器可能會把404響應體看成js來解析,試圖從裏面找出可用的東西。
用戶與Web服務器的距離會對響應時間產生影響。在多個地理位置分散的服務器上部署內容將使您的頁面從用戶的角度加載更快。
CDN是一羣不一樣地點的服務器,能夠更高效地分發內容到用戶。
Expries
或者 Cache-Control
頭這條規則有兩個方面:
Expires
頭實現「永不過時」策略Cache-Control
標頭來幫助瀏覽器處理條件請求頁面內容愈來愈豐富,意味着頁面中有更多腳本,樣式表,圖像以及Flash。您的頁面的首次訪問可能必須發出多個HTTP請求,但經過使用Expires標頭,您可使這些組件可緩存。
瀏覽器(和代理)使用緩存來減小HTTP請求的數量和大小,從而加快網頁加載速度。Web服務器使用HTTP響應中的Expires頭來告訴客戶端能夠緩存組件多長時間。 好比:
Expires: Thu, 15 Apr 2010 20:00:00 GMT
表示在2010-04-15均可以請求緩存內容。
經過前端工程師作出的決策,能夠顯著減小在網絡上傳輸HTTP請求和響應所需的時間。從HTTP / 1.1開始,Web客戶端表示支持使用HTTP請求中使用Accept-Encoding進行壓縮。
Accept-Encoding:gzip,deflate
若是服務器看到這個頭部,它可能會選用列表中的某個方法壓縮響應。服務器經過Content-Encoding
頭部提示客戶端:
Content-Encoding: gzip
gzip通常可減少響應的70%。儘量去gzip更多(文本)類型的文件。html,腳本,樣式,xml和json等等都應該被gzip,而圖片,pdf等等不該該被gzip,由於它們自己已被壓縮過,gzip壓縮它們只是浪費cpu,甚至增長文件大小。
儘量多地壓縮文件類型是減輕頁面重量和加速用戶體驗的簡便方法。
實體標記(ETag)是Web服務器和瀏覽器用於肯定瀏覽器緩存中的組件是否與源服務器上的組件匹配的機制。 添加ETag以提供驗證比上次修改日期更靈活的實體的機制。ETag是惟一標識組件的特定版本的字符串。 服務器這樣設置組件的ETag:
HTTP/1.1 200 OK Last-Modified: Tue, 12 Dec 2006 03:03:59 GMT ETag: "10c24bc-4ab-457e1c1f" Content-Length: 12195
以後,若是瀏覽器要驗證組件,它用If-None-Match
頭部來傳ETag給服務器。若是ETag匹配,服務器返回304:
GET /i/yahoo.gif HTTP/1.1 Host: us.yimg.com If-Modified-Since: Tue, 12 Dec 2006 03:03:59 GMT If-None-Match: "10c24bc-4ab-457e1c1f" HTTP/1.1 304 Not Modified
當用戶請求頁面時,後端服務器可能須要200到500毫秒才能將HTML頁面拼接在一塊兒。在此期間,瀏覽器在等待數據到達時處於空閒狀態。 在PHP中,有函數flush()
。它容許您將部分準備好的HTML響應發送到瀏覽器,以便瀏覽器能夠在後端忙於HTML頁面的其他部分時開始獲取組件。這種好處主要出如今繁忙的後端或輕量級前端。
一個比較好的flush的位置是在head
以後,由於瀏覽器能夠加載其中的樣式和腳本文件,然後臺繼續生成頁面剩餘部分。
<!-- css, js --> </head> <?php flush(); ?> <body> <!-- content -->
在雅虎郵件團隊發現,在使用時XMLHttpRequest
,POST在瀏覽器中實現爲兩步過程:首先發送頭部,而後發送數據。所以最好使用GET,它只須要一個TCP數據包發送(除非你有不少cookie)。IE中的最大URL長度爲2K,所以若是發送的數據超過2K,則可能沒法使用GET。
POST不提交任何數據跟GET行爲相似,但從語義上講,獲取數據應該用GET,提交數據到服務器用POST。
空src屬性的圖片的行爲可能跟你預期的不同。它有兩種形式:
<img src="">
var img = new Image(); img.src = "";
兩種形式都會產生相同的效果:瀏覽器向您的服務器發出另外一個請求
### 3.1 減少Cookie大小
http cookie的使用有多種緣由,好比受權和個性化。cookie的信息經過http頭部在瀏覽器和服務器端交換。儘量減少cookie的大小來下降響應時間。
當瀏覽器發出靜態圖像請求並將cookie與請求一塊兒發送時,服務器對這些cookie沒有任何用處。因此他們只是沒有充分理由建立網絡流量。您應該確保使用無cookie請求請求靜態組件。建立一個子域並在那裏託管全部靜態組件。
若是您的域名是www.example.org
,您能夠託管您的靜態組件static.example.org
。可是,若是您已經在頂級域上設置了cookie example.org
而不是www.example.org
,則全部請求都 static.example.org
將包含這些cookie。在這種狀況下,您能夠購買一個全新的域,在那裏託管您的靜態組件,並保持此域無cookie
在研究Yahoo!的性能時,咱們發現將樣式表移動到文檔HEAD會使頁面看起來加載速度更快。這是由於將樣式表放在HEAD中容許頁面逐步呈現。
關注性能的前端工程師但願頁面被逐步渲染,這時由於,咱們但願瀏覽器儘早渲染獲取到的任何內容。這對大頁面和網速慢的用戶很重要。給用戶視覺反饋,好比進度條的重要性已經被大量研究和記錄。在咱們的狀況中,HTML
頁面就是進度條。當瀏覽器逐步加載頁面頭部,導航條,logo等等,這些都是給等待頁面的用戶的視覺反饋。這優化了總體用戶體驗。
把樣式表放在文檔底部的問題是它阻止了許多瀏覽器的逐步渲染,包括IE。這些瀏覽器阻止渲染來避免在樣式更改時須要重繪頁面元素。因此用戶會卡在白屏。
CSS表達式是強大的(可能也是危險的)設置動態CSS屬性的方法。IE5開始支持,IE8開始不同意使用。例如,背景顏色能夠設置成每小時輪換:
background-color: expression( (new Date()).getHours()%2 ? "#B8D4FF" : "#F08A00" );
表達式的問題在於它們的評估頻率高於大多數人的預期。它們不只在頁面呈現和調整大小時進行從新計算,並且在頁面滾動時甚至在用戶將鼠標移動到頁面上時進行計算。在CSS表達式中添加計數器可讓咱們跟蹤CSS表達式的計算時間和頻率。在頁面上移動鼠標能夠輕鬆計算超過10,000次。
<link>
而不是@import
以前的一個最佳原則是說CSS應該在頂部來容許逐步渲染。
在IE用@import
和把CSS放到頁面底部行爲一致,因此最好別用。
專有的AlphaImageLoader
過濾器旨在解決IE版本<7中的半透明真彩色PNG的問題。該過濾器的問題在於它在下載圖像時阻止渲染並凍結瀏覽器。它還會增長內存消耗,而且每一個元素應用,而不是每一個圖像,所以問題成倍增長。
最佳作法是放棄AlphaImageLoader
,改用PNG8來優雅降級。
腳本引發的問題是它們阻塞了並行下載。 HTTP1.1規範建議瀏覽器每一個域名下不要一次下載超過2個組件。若是你的圖片分散在不一樣服務器,那麼你能並行下載多個圖片。但當腳本在下載,瀏覽器不會再下載其它組件,即便在不一樣域名下。
有些狀況下把腳本移動到底部並不簡單。好比,腳本中用了document.write
來插入內容,它就不能被移動到底部。另外有可能有做用域問題。但大多數狀況,有方法能夠解決這些問題。
一個替代建議是使用異步腳本。defer
屬性代表腳本不包含document.write
,是提示瀏覽器繼續渲染的線索。
在實際中使用外部文件一般會產生更快的頁面,由於瀏覽器會緩存JavaScript和CSS文件。每次請求HTML文檔時,都會下載HTML文檔中內聯的JavaScript和CSS。這減小了所需的HTTP請求數,但增長了HTML文檔的大小。另外一方面,若是JavaScript和CSS位於瀏覽器緩存的外部文件中,則HTML文檔的大小會減小,而不會增長HTTP請求的數量。
壓縮就是刪除代碼中沒必要要的字符來減少文件大小,從而提升加載速度。當代碼壓縮時,註釋刪除,不須要的空格(空白,換行,tab)也被刪除。
在一個頁面中兩次包含相同的JavaScript文件會損害性能。這並不像你想象的那麼不尋常。對美國十大頂級網站的評論顯示,其中兩個網站包含重複的腳本。兩個主要因素會增長腳本在單個網頁中重複的概率:團隊規模和腳本數量。當它發生時,重複的腳本會經過建立沒必要要的HTTP請求和浪費的JavaScript執行來損害性能。
發出沒必要要的http請求發生在IE而不是Firefox。在IE,若是外部腳本引入兩次且沒有緩存,它會發出2個請求。即便腳本被緩存,刷新時也會發出額外請求。
除了增長http請求,時間被浪費在執行腳本屢次上。無論IE仍是Firefox都會執行屢次。
使用JavaScript訪問DOM元素的速度很慢,所以爲了得到響應更快的頁面,您應該:
有時候頁面看起來不那麼響應(響應速度慢),是由於綁定到不一樣元素的大量事件處理函數執行太屢次。這是爲何使用_事件委託_是一種好方法。
另外,你沒必要等到onload
事件來開始處理DOM樹,DOMContentLoaded
更快。大多時候你須要的只是想訪問的元素已在DOM樹中,因此你沒必要等到全部圖片被下載。
pngcrush
或其它工具壓縮png。jpegtran
或其它工具壓縮jpeg。不要使用比您須要的更大的圖像,由於您能夠在HTML中設置寬度和高度。若是您須要, <img width="100" height="100" src="mycat.jpg" alt="My Cat" />
那麼您的圖像(mycat.jpg)應該是100x100px而不是縮小的500x500px圖像。
favicon.ico
小且可緩存favicon.ico是在你服務器根路徑的圖片。邪惡的是即便你不關心它,瀏覽器仍然會請求它。因此最好不要響應404。另外因爲在同一服務器,每次請求favicon.ico時也會帶上cookie。這個圖片還會影響下載順序,好比在IE,若是你在onload
時下載額外的組件,fcvicon會在這些組件以前被下載。
怎麼減輕favicon.ico的缺點?
此限制與iPhone不會緩存大於25K的組件這一事實有關。請注意,這是未壓縮的大小。在這裏減小組件大小很重要,由於單獨使用gzip可能還不夠。
將組件打包到多部分文檔就像帶有附件的電子郵件,它能夠幫助您經過一個HTTP請求獲取多個組件(請記住:HTTP請求很昂貴)。使用此技術時,首先檢查用戶代理是否支持它(iPhone不支持)。