【前端性能优化】雅虎35条军规
目錄
- 一、 Image
 - 1. 圖片優化
 - 2. CSS雪碧圖優化
 - 3. 禁止在HTML中縮放圖片
 - 4. 用小的且可以緩存的favicon
 
- 二、CSS
 - 5. 將css樣式放在頂部
 - 6. 避免CSS表達式
 - 7. 選擇而不是@import
 - 8. 避免使用(IE)過濾器
 
- 三、 Cookie
 - 9. 減少Cookie的體積
 - 10. 把組件放在不含cookie的域下
 
- 四、服務端
 - 11. 使用CDN
 - 12. 加Expires或者Cache-Control頭部
 - 13. 傳輸時用gzip等壓縮組件
 - 14. ETags 配置
 - 15. 早一點刷新buffer
 - 16. ajax請求用get
 - 17. 避免空src的圖片
 
- 五、JavaScript
 - 18. 把腳本放到底部
 - 19. 使用外部JS和CSS
 - 20. 壓縮JS和CSS
 - 21. 刪除重復的腳本
 - 22. 盡量減少DOM訪問
 - 23. 用智能的事件處理器
 
- 六、Mobile
 - 24. 保持組件小于25K
 - 25. 組件打包到一個多部分文檔
 
- 七、 Content
 - 26. 減少HTTP請求數
 - 27. 減少DNS查詢
 - 28. 避免重定向
 - 29. 讓Ajax可緩存
 - 30. 延遲加載組件
 - 31. 預加載組件
 - 32. 減少DOM數
 - 33. 把組件分散到不同的域名
 - 34. 最小化iframe的數量
 - 35. 杜絕404
 
前言
前端的性能優化可以說是非常的重要,下面就來看一下雅虎的35條軍規,這些規定可以給我們在想能優化方面提供一寫思路。英文水平高的可以直接看英文原文:鏈接
注意:所有文章中提到的組件泛指各種文件,如:HTML、CSS、JavaScript、圖片、視頻、音頻等。
一、 Image
1. 圖片優化
- 檢查 gif 圖片的調色板大小是否匹配圖片顏色數。
 - 可以把 gif 轉成 png 看看有沒有變小。除了動畫,gif 一般可以轉成 png8。
 - 運行 pngcrush 或其它工具壓縮 png。
 - 運行 jpegtran 或其它工具壓縮 jpeg。
 
2. CSS雪碧圖優化
- 把圖片橫向合并而不是縱向,橫向更小。
 - 把顏色近似的圖片合并到一張雪碧圖,這樣可以讓顏色數更少,如果低于 256 就可以用 png8。
 - Be mobile-friendly并且合并時圖片間的間距不要太大。這對圖片大小影響不是太大,但客戶端解壓時需要的內存更少。100×100是10000個像素,1000×1000是1000000個像素。
 
3. 禁止在HTML中縮放圖片
不要在 HTML 中縮放圖片。不要因為可以設置圖片的寬高就去用比需要的大得多的圖片。如果需要100x100px的圖片,那就不要用500x500px的。
4. 用小的且可以緩存的favicon
-  
favicon.ico是放在服務器根目錄的圖片,瀏覽器也會自動請求它,所以最好不要給一個404 Not Found響應。而且只要在同一個服務器上,每次請求它時都會發送cookie,此外這個圖片還會干擾下載順序,例如在IE中,當你在onload中請求額外組件時,將會先下載favicon。
 -  
所以為了緩解favicon.ico的缺點,應該確保:
- 足夠小,最好在1K以下
 - favicon.ico 一般是不進行更換的,所以我們可以給它設置Expires頭部,而且可以安全地設置為幾個月,避免每一次打開頁面都需要去進行請求。
 
 
二、CSS
5. 將css樣式放在頂部
將樣式表移到 <head> 里會讓頁面更快。這是因為把樣式表移到 <head> 里允許頁面逐步渲染。
我們希望頁面被逐步渲染,這是因為,我們希望瀏覽器盡早渲染獲取到內容。這對大頁面和網速慢的用戶很重要。給用戶視覺反饋,比如進度條就非常重要,HTML 頁面就是進度條。當瀏覽器逐步加載頁面頭部,導航條,logo 等,這些都是給等待頁面的用戶的視覺反饋。這優化了整體用戶體驗。
把樣式表放在文檔底部的問題是它阻止了許多瀏覽器的逐步渲染,包括 IE。這些瀏覽器阻止渲染來避免在樣式更改時需要重繪頁面元素。所以用戶會卡在白屏。
6. 避免CSS表達式
CSS 表達式是強大的(可能也是危險的)設置動態 CSS 屬性的方法。
CSS 表達式的問題是它們可能比預期計算的更頻繁。它們不僅在頁面載入和調整大小時重新計算,也在滾動頁面甚至是用戶在頁面上移動鼠標時計算。比如在頁面上移動鼠標可能輕易計算超過10000次。
要避免CSS表達式計算太多次,可以在它第一次計算后替換成確切值,或者用事件處理函數而不是CSS表達式。
7. 選擇而不是@import
之前的一個最佳原則是說 CSS 應該在頂部來允許逐步渲染。
在 IE 用 @import 和把 CSS 放到頁面底部行為一致,所以最好別用。
8. 避免使用(IE)過濾器
IE專有的AlphaImageLoader過濾器用于修復IE7以下版本的半透明真彩色PNG的問題。這個過濾器的問題是它阻止了渲染,并在圖片下載時凍結了瀏覽器。另外它還引起內存消耗,并且它被應用到每個元素而不是每個圖片,所以問題變得更嚴重了。
最佳做法是放棄 AlphaImageLoader,改用 PNG8 來降級。
三、 Cookie
9. 減少Cookie的體積
HTTP Cookie 的使用有多種原因,比如授權和個性化。Cookie 的信息通過 http 頭部在瀏覽器和服務器端交換。我們可以對Cookie做如下優化:
- 消除不必要的 Cookie。
 - 盡可能減小 Cookie 的大小來降低響應時間。
 - 注意設置 Cookie 到合適的域名級別,則其它子域名不會被影響。
 - 正確設置 Expires 日期。早一點的 Expires 日期或者沒有盡早的刪除 Cookie,優化響應時間。
 
10. 把組件放在不含cookie的域下
當瀏覽器請求靜態圖片并把 cookie 一起發送到服務器時,cookie 此時對服務器沒什么用處。所以這些 cookie 只是增加了網絡流量。所以應該保證靜態組件的請求是沒有 cookie 的。可以創建一個子域名來托管所有靜態組件。
比如,域名是www.example.org,可以把靜態組件托管在static.example.org。不過,如果把cookie設置在頂級域名 example.org 下,這些cookie仍然會被傳給static.example.org。這種情況下,啟用一個全新的域名來托管靜態組件。注意:因為cookie是可以跨二級域名的,所以如果你設置的頂級域名是example.org,那么static.example.org 也是可以被訪問到的,因此需要啟用一個全新的域名。
另外一個用沒有 cookie 的域名提供組件的好處是,某些代理可能會阻止緩存帶 cookie 的靜態組件請求。
四、服務端
11. 使用CDN
用戶接近服務器就會減少響應時間。把內容發布到多個地理上分散的服務器可以讓頁面加載更快。
80-90%的終端用戶響應時間花費在下載頁面中的所有組件:圖片、樣式、腳本、falsh 等。這是_Performance Golden Rule_。首先分發靜態內容。這不僅可以減少響應時間,用CDN還很容易來做。
CDN 是一群不同地點的服務器,可以更高效地分發內容到用戶。
12. 加Expires或者Cache-Control頭部
這條規則有兩個方面:
- 對靜態組件:通過設置 Expires 頭部來實現“永不過期”策略。
 - 對動態組件:用合適的 Cache-Control 頭部來幫助瀏覽器進行有條件請求。
 
頁面越來越豐富,意味著更多腳本,樣式,圖片等。第一次訪問的用戶可能需要發出多個請求,但使用Expires可以讓這些組件被緩存。這避免了訪問子頁面時沒必要的 http 請求。Expires 一般用在圖片上,但應該用在所有的組件上。
瀏覽器(以及代理)使用緩存來減少http請求數,加快頁面加載。服務器使用http響應的Expires頭部來告訴客戶端一個組件可以緩存多久。
注意,如果設置了Expires頭部,當組件更新后,必須更改文件名。
13. 傳輸時用gzip等壓縮組件
http 請求或響應的傳輸時間可以被顯著減少。壓縮可以通過減少 http 響應的大小減少響應時間。
從 HTTP/1.1 開始,客戶端通過http請求中的 Accept-Encoding 頭部來提示支持的壓縮:
Accept-Encoding: gzip, deflate如果服務器看到這個頭部,它可能會選用列表中的某個方法壓縮響應。服務器通過Content-Encoding 頭部提示客戶端:
Content-Encoding: gzipgzip 一般可減小響應的 70%。盡可能去gzip更多(文本)類型的文件。html,腳本,樣式,xml 和json 等都應該被gzip,而圖片,pdf等不應該被gzip,因為它們本身已被壓縮過,gzip 它們只是浪費 cpu,甚至增加文件大小。
14. ETags 配置
實體標記(Entity tags,簡稱ETag)是服務器和瀏覽器之間判斷瀏覽器緩存中某個組件是否匹配服務器端原組件的一種機制。實體就是組件:圖片,腳本,樣式等。ETag被當作驗證實體的比最后更改(last-modified)日期更高效的機制。服務器這樣設置組件的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 ModifiedETag 的問題是它們被構造來使它們對特定的運行這個網站的唯一服務器。瀏覽器從一個服務器獲取組件,之后向另一個服務器驗證,ETag 將不匹配。然而服務器集群是處理請求的通用解決方案。
如果不能解決多服務器間的 ETag 匹配問題,那么刪除 ETag 可能更好。
15. 早一點刷新buffer
當用戶請求一個頁面,服務器一般要花 200-500ms 來渲染整個頁面。這段時間,瀏覽器是空閑的(等待數據返回)。在 php種,有個方法 flush() 允許你傳輸部分準備好的 html 響應給瀏覽器。這樣的話瀏覽器就可以開始下載組件,而同時后臺可以繼續生成頁面剩下的部分。這種好處更多是在忙碌的后臺或輕前端網站可以看到。
一個比較好的 flush 的位置是在 head 之后,因為瀏覽器可以加載其中的樣式和腳本文件,而后臺繼續生成頁面剩余部分。
16. ajax請求用get
Yahoo! Mail團隊發現當使用 XMLHttpRequest,POST請求被瀏覽器實現為兩步:首先發送頭部,然后發送數據。所以使用 GET 最好,僅用一個 TCP 包發送(除非cookie太多)。IE的url長度限制是2K。
如果POST不提交任何數據,那它跟 GET 行為類似。但從語義上講,獲取數據應該用 GET,提交數據到服務器用 POST。
17. 避免空src的圖片
空src屬性的圖片的行為有兩種形式:
- html標簽: <img src="">
 - js:var img = new Image(); img.src = "";
 
上面的兩種形式都會造成同一種后果:瀏覽器會向你的服務器發請求。
IE向頁面所在的目錄發請求。 Safari 和 Chrome 請求實際的頁面。 FireFox3 及之前和Safari/Chrome 一樣,但從3.5開始修復問題不再發送請求。 Opera 遇到空圖片 src 不做任何事。
發送大量的意料之外的流量,會削弱服務器,甚至可能會破壞用戶數據。如果你在跟蹤請求狀態,通過 cookie 或其它,可能會破壞數據。即使 image 的請求不會返回圖片,但所有的頭部數據都被瀏覽器讀取了,包括 cookie。即使剩下的響應體被丟棄,破壞可能已經發生。 這種行為的根源是 uri 解析發生在瀏覽器。
RFC 3986 定義了這種行為,空字符串被當作相對路徑,Firefox, Safari, 和 Chrome都正確解析,而IE錯誤??傊?#xff0c;瀏覽器解析空字符串為相對路徑的行為被認為是符合預期的。
html5在_4.8.2_添加了對標簽src屬性的描述,指導瀏覽器不要發出額外的請求。幸運的是將來瀏覽器不會有這個問題了(僅在圖片上)。不幸的是,<script src="">和<link href="">沒有這樣的規范。
五、JavaScript
18. 把腳本放到底部
腳本引起的問題是它們阻塞了并行下載。HTTP1.1 規范建議瀏覽器每個域名下不要并行下載超過2個組件。如果你的圖片分散在不同服務器,那么你能并行下載多個圖片。但當腳本在下載的時候,瀏覽器不會再下載其它文件,即使在不同域名下。
有些情況下把腳本移動到底部并不簡單。比如,腳本中用了 document.write 來插入內容,它就不能被移動到底部。另外有可能有作用域問題。但大多數情況,有方法可以解決這些問題。
一個替代建議是使用異步腳本。defer 屬性表明腳本不包含 document.write,是提示瀏覽器繼續渲染的線索。不幸的是,Firefox 不支持。如果腳本能異步,那么也就可以移動到底部,這樣可以大大加快網頁運行速度。
這里要注意JavaScript是會阻塞瀏覽器運行的,所以腳本文件盡量放到頁面的最下面。
19. 使用外部JS和CSS
JS 和 CSS 是應該包含在外部文件還是內聯在頁面本身?
使用外部文件一般會加快頁面,因為 JS 和 CSS 文件被瀏覽器緩存了。內聯的 JS 和CSS 怎在每次 HTML 文檔下載時都被下載。內聯減少了http請求,但增加了HTML文檔大小。另一方面,如果 JS 和 CSS 被緩存了,那么 HTML 文檔可以減小大小而不增加 HTTP 請求。
核心因素就是 JS 和 CSS 被緩存相對于 HTML 文檔被請求的頻率。如果網站用戶每個會話打開了多個頁面,許多頁面重復使用相同的 JS 和CSS,那么有很大可能用外部 JS 和 CSS 更好。
許多網站用這些指標計算后在中間位置。對這些網站來說,最佳方案還是用外部 JS 和 CSS 文件。唯一例外是內聯更被主頁偏愛,如http://www.yahoo.com/。主頁每個會話可能只會打開少量甚至一個頁面,這時候內聯可能更快。
注意,需要根據實際業務來選擇內聯還是外聯。(內聯就是直接寫在HTML文件的js或者css,外聯就是引入的js或者css文件)
20. 壓縮JS和CSS
壓縮就是刪除代碼中不必要的字符來減小文件大小,從而提高加載速度。當代碼壓縮時,注釋刪除,不需要的空格(空白,換行,tab)也被刪除。
混淆是對代碼可選的優化。它比壓縮更復雜,并且可能產生 bug。在對美國 top10 網站的調查,壓縮可減小 21%,而混淆可減小 25%。
除了外部腳本和樣式,內聯的腳本和樣式同樣應該被壓縮。
21. 刪除重復的腳本
在頁面中引入相同的腳本兩次會降低性能。當確實引入重復腳本,會發出不必要的http請求和浪費js執行時間。
發出不必要的 http 請求發生在 IE 而不是 Firefox。在 IE,如果外部腳本引入兩次且沒有緩存,它會發出2個請求。即使腳本被緩存,刷新時也會發出額外請求。
除了增加http請求,時間被浪費在執行腳本多次上。不管IE還是Firefox都會執行多次。
一種避免多次引入腳本的方法是在模板系統實現一個腳本管理模塊。
22. 盡量減少DOM訪問
用 JS 訪問 DOM 元素很慢,所以為了響應更好的頁面,應該:
- 緩存訪問過的元素的引用
 - 在 DOM 樹外更新節點,然后添加到 DOM 樹
 - 避免用 JS 實現固定布局
 
注意,能用CSS解決的事情,就盡量不用JS操作DOM,DOM操作開銷很大。
23. 用智能的事件處理器
有時候頁面看起來響應速度比較慢,是因為綁定到不同元素的大量事件處理函數執行太多次。一種更好的解決方法就是使用事件委托。
另外,不必等到 onload 事件來開始處理 DOM 樹,使用DOMContentLoaded 會更快。大多時候我們需要的只是想訪問的元素已在 DOM 樹中,所以不必等到所有圖片下載完。
注意:
- onLoad是的在頁面所有文件加載完成后執行
 - DomContentLoad是Dom加載完成后執行,不必等待樣式腳本和圖片加載
 
六、Mobile
24. 保持組件小于25K
這個限制與 iPhone 不緩存大于 25K 的組件相關。
25. 組件打包到一個多部分文檔
將組件打包到多部分文檔就像帶有附件的電子郵件,它可以幫助您通過一個 HTTP 請求獲取多個組件(請記住:HTTP 請求很昂貴)。使用此技術時,首先檢查用戶代理是否支持它( iPhone 不支持)。
七、 Content
26. 減少HTTP請求數
到終端用戶的響應時間 80% 花在前端:大部分用于下載組件 js/css/image/flash 等。減少組件數就是減少渲染頁面所需的 http 請求數。這是讓頁面更快的關鍵。
減少組件數的一個方法就是簡化頁面設計。保持富內容的頁面且能減少 http 請求,有以下幾個技術:
-  
Combined files (合并文件):如合并 js,合并 css 都能減少請求數。如果頁面間腳本和樣式差異很大,合并會更具挑戰性,同時也這樣也可以減少發布所需要的時間。
 -  
CSS Sprites:雪碧圖可以合并多個背景圖片,通過 background-image 和 background-position 來顯示不同部分。
 -  
Image maps (雪碧圖):合并多個圖片到一個圖片,一般用于如導航條。由于定義坐標的枯燥和易錯,一般不推薦。
 -  
Inline images (內聯圖片):使用 data:url scheme 來內聯圖片,將內嵌圖像組合到(緩存的)樣式表中同樣也是一種減少 HTTP 請求并避免增加頁面大小的方法。
 
減少請求數是為第一次訪問頁面的用戶提高性能的最重要的指導。
注意,Inline images 這里我們一些矢量圖標轉換為base64編碼,然后直接內嵌到HTML文件或者CSS文件當中,減少http請求。
27. 減少DNS查詢
在瀏覽器地址欄輸入網址,通過 DNS 查詢得到網站真實 IP。
DNS 查詢被緩存來提高性能。這種緩存可能發生在特定的緩存服務器(ISP/local area network維護),或者用戶的計算機。DNS 信息留存在操作系統 DNS 緩存中。大多瀏覽器有自己的緩存,獨立于操作系統緩存。只要瀏覽器在自己的緩存里有某條DNS 記錄,它就不會向操作系統發 DNS 解析請求。
IE默認緩存 DNS 記錄30分鐘,FireFox 默認緩存1分鐘。
當客戶端的 DNS 緩存是空的,DNS 查找次數等于頁面中的唯一域名數。
減少DNS請求數可能會減少并行下載數。避免 DNS 查找減少響應時間,但減少并行下載數可能會增加響應時間。指導原則是組件可以分散在至少2個但不多于4個的不同域名。這是這兩者的一個平衡點。
28. 避免重定向
跳轉用301或302狀態碼來達成。一個301響應 http 頭的例子:
HTTP/1.1 301 Moved Permanently Location: http://example.com/newuri Content-Type: text/html瀏覽器自動跳轉到 Location 指定的路徑。跳轉所需的所有信息都在 http 頭,所以 http 主體一般是空的。301 302響應一般不會被緩存,除非有額外的頭部信息,比如 Expires 或 Cache-Control 指定要緩存。meta 刷新標簽或 JavaScript 也可以跳轉,但如果真要跳轉,3xx跳轉更好,主要是保證返回鍵可用。
最重要的是重定向會降低用戶體驗。在用戶和 HTML 文檔之間插入重定向會延遲頁面中的所有內容,因為頁面中的任何內容都無法呈現,并且在 HTML 文檔到達之前不會開始下載任何組件。
最浪費的跳轉之一發生在url尾部斜杠(/)缺失。比如http://astrology.yahoo.com/astrology會301跳轉到http://astrology.yahoo.com/astrology/。這可以被Apache等服務器修復,如果您使用的是Apache處理程序,則可以使用Aliasor mod_rewrite或DirectorySlash指令在Apache中修復此問題。
29. 讓Ajax可緩存
使用 ajax 的好處是可以向用戶提供很快的反饋,因為它是向后臺異步請求數據。但是,這些異步請求不保證用戶等待的時間——異步不意味著瞬時。
提高ajax性能的最重要的方法是讓響應被緩存,即在上面第12條中討論的 Expires 。其它方法是:
- gzip 組件
 - 減少 DNS 查找
 - 壓縮 JS
 - 避免跳轉
 - 設置 ETags
 
30. 延遲加載組件
我們要考慮,什么是頁面初始化必須。,然后,剩下的內容和組件可以延遲加載。
JavaScript 是理想的(延遲)候選者,可以切分到 onload 事件之前和之后。比如拖放的 js 庫可以延遲,因為拖動必須在頁面初始化之后。其它可延遲的包括隱藏的內容,折疊起來的圖片等。
31. 預加載組件
預加載看起來與延遲加載相反,但它的確有個不同的目標。通過預加載可以利用瀏覽器的空閑時間來請求你將來會用到的組件。這樣當用戶訪問下一個頁面時,會有更多的組件已經在緩存中,這樣會極大加快頁面加載。
有幾種預加載類型:
- 無條件預加載:一旦 onload 觸發,你立即獲取另外的組件。比如谷歌會在主頁這樣加載搜索結果頁面用到的雪碧圖。
 - 有條件預加載:基于用戶動作,推測用戶下一步會去哪里并加載相應組件。
 - 預期的預加載:在發布重新設計的網站前提前加載。在舊網頁預加載新網頁的部分組件,那么切換到新網頁時就不會是沒有任何緩存了。
 
32. 減少DOM數
一個復雜的頁面意味著更多的內容要下載,以及更慢的 dom 訪問。比如在有 500dom 數量的頁面添加事件處理就和有 5000dom 數量的不同。
如果頁面 dom 元素很多,那么意味著可能需要刪除無用的內容和標簽來優化。
33. 把組件分散到不同的域名
把組件分散到不同的域名允許你最大化并行下載數。由于 DNS 查詢的副作用,最佳的不同域名數是2-4。
34. 最小化iframe的數量
iframe 允許 html 文檔被插入到父文檔。
<iframe>優點:
- 幫助解決緩慢的第三方內容的加載,如廣告和徽章
 - 并行下載腳本
 
<iframe>缺點:
- 即使空的也消耗(資源和時間)
 - 阻塞了頁面的onload
 - 非語義化(標簽)
 
35. 杜絕404
http 請求是昂貴的,所以發出 http 請求但獲得沒用的響應(如404)是完全不必要的,并且會降低用戶體驗。
一些網站會有特別的 404 頁面提高用戶體驗,但這仍然會浪費服務器資源。特別壞的是當鏈接指向外部 js 但卻得到 404 結果。這樣首先會占用并行下載數,其次瀏覽器可能會把 404 響應體當作 js 來解析,試圖從里面找出可用的東西。
最后
隨著Vue、React等框架的出現,上面的一些規則可能已經不適用了,但是這為我們在性能優化方面提供了一個出發點。我們現在用到的CDN、HTTP緩存、懶加載、預加載、服務端渲染等性能優化手段,和上面這些軍規都有或多或少的關聯。更多性能優化的手段需要我們去探索~
總結
以上是生活随笔為你收集整理的【前端性能优化】雅虎35条军规的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: 《把时间当作朋友》 - 书评
 - 下一篇: vb.net怎么和mysql连接_解析V