雅虎前端優化35條規則

本文是大名鼎鼎的雅虎前端優化規則(Yslow)的翻譯。翻譯並不逐字逐句,部分難以逐字翻譯的被意譯了,另一些不重要的舉例等也被精簡。php

原文: Best Practices for Speeding Up Your Web Sitecss

如何讓web頁面更快,雅虎團隊實踐總結了7類35條規則,下面一一列出。html

1. Content

1.1 Make Fewer HTTP Requests

Minimize HTTP Requests減小/最小化 http 請求數。前端

到終端用戶的響應時間80%花在前端:大部分用於下載組件(js/css/image/flash等等)。減小組件數就是減小渲染頁面所需的http請求數。這是更快頁面的關鍵。html5

減小組件數的一個方法就是簡化頁面設計。保持富內容的頁面且能減小http請求,有如下幾個技術:web

  • Combined files。合併文件,如合併js,合併css都能減小請求數。若是頁面間腳本和樣式差別很大,合併會更具挑戰性。
  • CSS Sprites。雪碧圖能夠合併多個背景圖片,經過background-image 和 background-position 來顯示不一樣部分。
  • Image maps。合併多個圖片到一個圖片,通常用於如導航條。因爲定義座標的枯燥和易錯,通常_不推薦_。
  • Inline images。使用data:url scheme來內連圖片。

減小請求數是爲第一次訪問頁面的用戶提升性能的最重要的指導。ajax

1.2 Reduce DNS Lookups

減小DNS查詢。express

就像電話簿,你在瀏覽器地址欄輸入網址,經過DNS查詢獲得網站真實IP。json

DNS查詢被緩存來提升性能。這種緩存可能發生在特定的緩存服務器(ISP/local area network維護),或者用戶的計算機。DNS信息留存在操做系統DNS緩存中(在windows中就是 DNS Client Serve )。大多瀏覽器有本身的緩存,獨立於操做系統緩存。只要瀏覽器在本身的緩存裏有某條DNS記錄,它就不會向操做系統發DNS解析請求。windows

IE默認緩存DNS記錄30分鐘,FireFox默認緩存1分鐘。

當客戶端的DNS緩存是空的,DNS查找次數等於頁面中的惟一域名數。

減小DNS請求數可能會減小並行下載數。避免DNS查找減小響應時間,但減小並行下載數可能會增長響應時間。指導原則是組件能夠分散在至少2個但很少於4個的不一樣域名。這是二者的妥協。

1.3 Avoid Redirects

避免跳轉。

跳轉用301302狀態碼來達成。一個301響應http頭的例子:

HTTP/1.1 301 Moved Permanently
Location: http://example.com/newuri
Content-Type: text/html

瀏覽器自動跳轉到Location指定的路徑。跳轉所需的全部信息都在http頭,因此http主體通常是空的。301 302響應通常不會被緩存,除非有額外的頭部信息,好比ExpiresCache-Control指定要緩存。meta刷新標籤或 JavaScript 也能夠跳轉,但若是真要跳轉,3xx跳轉更好,主要是保證返回鍵可用。

跳轉顯然拖慢響應速度。在跳轉的頁面被獲取前瀏覽器沒什麼能渲染,沒什麼組件能下載。

最浪費的跳轉之一發生在url尾部slash(/)缺失。好比http://astrology.yahoo.com/astrology301跳轉到http://astrology.yahoo.com/astrology/。這能夠被Apache等服務器修復,用Aliasmod_rewrite等等。

1.4 Make Ajax Cacheable

讓Ajax可緩存。

使用ajax的好處是能夠向用戶提供很快的反饋,由於它是向後臺異步請求數據。可是,這些異步請求不保證用戶等待的時間——異步不意味着瞬時。

提升ajax性能的最重要的方法是讓響應被緩存,即在Add an Expires or a Cache-Control Header中討論的 Expires 。其它方法是:

  • gzip組件
  • 減小DNS查找
  • 壓縮JS
  • 避免跳轉
  • 設置ETags

1.5 Post-load Components

延遲加載組件。

再看看你的頁面而後問問本身,「什麼是頁面初始化必須的?」。剩下的內容和組件能夠延遲。

JavaScript是理想的(延遲)候選者,能夠切分到onload事件以前和以後。好比拖放的js庫能夠延遲,由於拖動必須在頁面初始化以後。其它可延遲的包括隱藏的內容,摺疊起來的圖片等等。

1.6 Preload Components

預加載組件。

預加載看起來與延遲加載相反,但它的確有個不一樣的目標。經過預加載你能夠利用瀏覽器的空閒時間來請求你未來會用到的組件。這樣當用戶訪問下一個頁面時,你會有更多的組件已經在緩存中,這樣會極大加快頁面加載。

有幾種預加載類型:

  • 無條件預加載:一旦onload觸發,你當即獲取另外的組件。好比谷歌會在主頁這樣加載搜索結果頁面用到的雪碧圖。
  • 有條件預加載:基於用戶動做,你推測用戶下一步會去哪裏並加載相應組件。
  • 預期的預加載:在發佈從新設計(的網站)前提早加載。在舊網頁預加載新網頁的部分組件,那麼切換到新網頁時就不會是沒有任何緩存了。

1.7 Reduce the Number of DOM Elements

減小dom數。

一個複雜的頁面意味着更多的內容要下載,以及更慢的dom訪問。好比在有500dom數量的頁面添加事件處理就和有5000dom數量的不一樣。

若是你的頁面dom元素不少,那麼意味着你可能須要刪除無用的內容和標籤來優化。

1.8 Split Components Across Domains

把組件分散到不一樣的域名。

把組件分散到不一樣的域名容許你最大化並行下載數。因爲DNS查詢的反作用,最佳的不一樣域名數是2-4。

1.9 Minimize the Number of iframes

最小化iframe的數量。

iframe容許html文檔被插入到父文檔。

<iframe>優勢:

  • 幫助解決緩慢的第三方內容的加載,如廣告和徽章
  • 安全沙盒
  • 並行下載腳本

<iframe>缺點:

  • 即便空的也消耗(資源和時間)
  • 阻塞了頁面的onload
  • 非語義化(標籤)

1.10 No 404s

不要404。

http請求是昂貴的,因此發出http請求但得到沒用的響應(如404)是徹底沒必要要的,而且會下降用戶體驗。

一些網站會有特別的404頁面提升用戶體驗,但這仍然會浪費服務器資源。特別壞的是當連接指向外部js但卻獲得404結果。這樣首先會下降(佔用)並行下載數,其次瀏覽器可能會把404響應體看成js來解析,試圖從裏面找出可用的東西。

2. Server

2.1 Use a Content Delivery Network

使用CDN。

用戶接近你的服務器會減小響應時間。把你的內容發佈到多個,地理上分散的服務器可讓頁面加載更快。但怎麼開始?

首先不要試圖把你的架構從新設計成分佈式架構。由於可能引進更多複雜性和不可控。

記住80-90%的終端用戶響應時間花費在下載頁面中的全部組件:圖片、樣式、腳本、falsh等等。這是_Performance Golden Rule_。不要從困難的從新設計後臺架構開始,最好首先分發你的靜態內容。這不只能夠減小響應時間,用CDN還很容易來作。

CDN是一羣不一樣地點的服務器,能夠更高效地分發內容到用戶。一些大公司有本身的CDN。

2.2 Add an Expires or a Cache-Control Header

Expires或者Cache-Control頭部。

這條規則有兩個方面:

  • 對靜態組件:經過設置Expires頭部來實現「永不過時」策略。
  • 對動態組件:用合適的Cache-Control頭部來幫助瀏覽器進行有條件請求。

頁面愈來愈豐富,意味着更多腳本,樣式,圖片等等。第一次訪問的用戶可能須要發出多個請求,但使用Expires可讓這些組件被緩存。這避免了訪問子頁面時不必的http請求。Expires通常用在圖片上,但應該用在全部的組件上。

瀏覽器(以及代理)使用緩存來減小http請求數,加快頁面加載。服務器使用http響應的Expires頭部來告訴客戶端一個組件能夠緩存多久。好比下面:

Expires: Thu, 15 Apr 2010 20:00:00 GMT //2010-04-15以前都是穩定的

注意,若是你設置了Expires頭部,當組件更新後,你必須更改文件名。

2.3 Gzip Components

傳輸時用gzip等壓縮組件。

http請求或響應的傳輸時間能夠被前端工程師顯著減小。終端用戶的帶寬,ISP,接近對等交換點等等無法被開發團隊控制,可是,壓縮能夠經過減小http響應的大小減小響應時間。

HTTP/1.1開始,客戶端經過http請求中的Accept-Encoding頭部來提示支持的壓縮:

Accept-Encoding: gzip, deflate

若是服務器看到這個頭部,它可能會選用列表中的某個方法壓縮響應。服務器經過Content-Encoding頭部提示客戶端:

Content-Encoding: gzip

gzip通常可減少響應的70%。儘量去gzip更多(文本)類型的文件。html,腳本,樣式,xml和json等等都應該被gzip,而圖片,pdf等等不該該被gzip,由於它們自己已被壓縮過,gzip它們只是浪費cpu,甚至增長文件大小。

2.4 Configure 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 Modified

ETag的問題是它們被構造來使它們對特定的運行這個網站的服務器惟一。瀏覽器從一個服務器獲取組件,以後向另外一個服務器驗證,ETag將不匹配。然而服務器集羣是處理請求的通用解決方案。

若是不能解決多服務器間的ETag匹配問題,那麼刪除ETag可能更好。

2.5 Flush the Buffer Early

早一點刷新buffer(儘早給瀏覽器數據)。

當用戶請求一個頁面,服務器通常要花200-500ms來拼湊整個頁面。這段時間,瀏覽器是空閒的(等數據返回)。在php,有個方法flush()容許你傳輸部分準備好的html響應給瀏覽器。這樣的話瀏覽器就能夠開始下載組件,而同時後臺能夠繼續生成頁面剩下的部分。這種好處更可能是在忙碌的後臺或輕前端網站能夠看到。

一個比較好的flush的位置是在head以後,由於瀏覽器能夠加載其中的樣式和腳本文件,然後臺繼續生成頁面剩餘部分。

<!-- css, js --> </head> <?php flush(); ?> <body> <!-- content -->

2.6 Use GET for AJAX Requests

ajax請求用get。

Yahoo! Mail團隊發現當使用XMLHttpRequest,POST 被瀏覽器實現爲兩步:首先發送頭部,而後發送數據。因此使用GET最好,僅用一個TCP包發送(除非cookie太多)。IE的url長度限制是2K。

POST但不提交任何數據根GET行爲相似,但從語義上講,獲取數據應該用GET,提交數據到服務器用POST。

2.7 Avoid Empty Image src

避免空src的圖片。

空src屬性的圖片的行爲可能跟你預期的不同。它有兩種形式:

  1. html標籤:<img src="">
  2. js:var img = new Image(); img.src = "";

兩種都會形成同一種後果:瀏覽器會向你的服務器發請求。

  • IE,向頁面所在的目錄發請求。
  • Safari和Chrome,請求實際的頁面。
  • FireFox3及以前和Safari/Chrome同樣,但從3.5開始修復問題,再也不發請求。
  • Opera遇到空圖片src不作任何事。

爲何這種行爲很糟糕?

  1. 因爲發送大量的意料以外的流量,會削弱服務器,尤爲那些天天pv上百萬的頁面。
  2. 浪費服務器計算週期取生成不會被瀏覽的頁面。
  3. 可能會破壞用戶數據。若是你在跟蹤請求狀態,經過cookie或其它,你可能會破壞數據。即便image的請求不會返回圖片,但全部的頭部數據都被瀏覽器讀取了,包括cookie。即便剩下的響應體被丟棄,破壞可能已經發生。

這種行爲的根源是uri解析發生在瀏覽器。RFC 3986 定義了這種行爲,空字符串被看成相對路徑,Firefox, Safari, 和 Chrome都正確解析,而IE錯誤。總之,瀏覽器解析空字符串爲相對路徑的行爲被認爲是符合預期的。

html5在_4.8.2_添加了對標籤src屬性的描述,指導瀏覽器不要發出額外的請求。

The src attribute must be present, and must contain a valid URL referencing a non-interactive, optionally animated, image resource that is neither paged nor scripted. If the base URI of the element is the same as the document's address, then the src attribute's value must not be the empty string.

幸運的是未來瀏覽器不會有這個問題了(在圖片上)。不幸的是,<script src=""><link href="">沒有這樣的規範。

3 Cookie

3.1 Reduce Cookie Size

http cookie的使用有多種緣由,好比受權和個性化。cookie的信息經過http頭部在瀏覽器和服務器端交換。儘量減少cookie的大小來下降響應時間。

  • 消除沒必要要的cookie。
  • 儘量減少cookie的大小來下降響應時間。
  • 注意設置cookie到合適的域名級別,則其它子域名不會被影響。
  • 正確設置Expires日期。早一點的Expires日期或者沒有會盡早刪除cookie,優化響應時間。

3.2 Use Cookie-free Domains for Components

用沒有cookie的域名提供組件。

當瀏覽器請求靜態圖片並把cookie一塊兒發送到服務器時,cookie此時對服務器沒什麼用處。因此這些cookie只是增長了網絡流量。因此你應該保證靜態組件的請求是沒有cookie的。能夠建立一個子域名來託管全部靜態組件。

好比,你域名是www.example.org,能夠把靜態組件託管在static.example.org。不過,你若是把cookie設置在頂級域名example.org下,這些cookie仍然會被傳給static.example.org。這種狀況下,啓用一個全新的域名來託管靜態組件。

另一個用沒有cookie的域名提供組件的好處是,某些代理可能會阻止緩存待cookie的靜態組件請求。

4. CSS

4.1 Put Stylesheets at the Top

把樣式放在頂部。

研究雅虎網頁性能時發現把樣式表移到<head>裏會讓頁面更快。這是由於把樣式表移到<head>裏容許頁面逐步渲染。

關注性能的前端工程師但願頁面被逐步渲染,這時由於,咱們但願瀏覽器儘早渲染獲取到的任何內容。這對大頁面和網速慢的用戶很重要。給用戶視覺反饋,好比進度條的重要性已經被大量研究和記錄。在咱們的狀況中,HTML頁面就是進度條。當瀏覽器逐步加載頁面頭部,導航條,logo等等,這些都是給等待頁面的用戶的視覺反饋。這優化了總體用戶體驗。

把樣式表放在文檔底部的問題是它阻止了許多瀏覽器的逐步渲染,包括IE。這些瀏覽器阻止渲染來避免在樣式更改時須要重繪頁面元素。因此用戶會卡在白屏。

HTML規範清楚代表樣式應該在<head>裏。

4.2 Avoid CSS Expressions

避免CSS表達式。

CSS表達式是強大的(可能也是危險的)設置動態CSS屬性的方法。IE5開始支持,IE8開始不同意使用。例如,背景顏色能夠設置成每小時輪換:

background-color: expression( (new Date()).getHours()%2 ? "#B8D4FF" : "#F08A00" );

CSS表達式的問題是它們可能比大多數人預期的計算的更頻繁。它們不只在頁面載入和調整大小時從新計算,也在滾動頁面甚至是用戶在頁面上移動鼠標時計算。好比在頁面上移動鼠標可能輕易計算超過10000次。

要避免CSS表達式計算太屢次,能夠在它第一次計算後替換成確切值,或者用事件處理函數而不是CSS表達式。

4.3 Choose <link> over @import

選擇<link>而不是@import

以前的一個最佳原則是說CSS應該在頂部來容許逐步渲染。

在IE用@import和把CSS放到頁面底部行爲一致,因此最好別用。

4.4 Avoid Filters

避免使用(IE)過濾器。

IE專有的AlphaImageLoader過濾器用於修復IE7如下版本的半透明真彩色PNG的問題。這個過濾器的問題是它阻止了渲染,並在圖片下載時凍結了瀏覽器。另外它還引發內存消耗,而且它被應用到每一個元素而不是每一個圖片,因此問題(的嚴重性)翻倍了。

最佳作法是放棄AlphaImageLoader,改用PNG8來優雅降級。

5. JavaScript

5.1 Put Scripts at the Bottom

把腳本放到底部。

腳本引發的問題是它們阻塞了並行下載。HTTP1.1規範建議瀏覽器每一個域名下不要一次下載超過2個組件。若是你的圖片分散在不一樣服務器,那麼你能並行下載多個圖片。但當腳本在下載,瀏覽器不會再下載其它組件,即便在不一樣域名下。

有些狀況下把腳本移動到底部並不簡單。好比,腳本中用了document.write來插入內容,它就不能被移動到底部。另外有可能有做用域問題。但大多數狀況,有方法能夠解決這些問題。

一個替代建議是使用異步腳本。defer屬性代表腳本不包含document.write,是提示瀏覽器繼續渲染的線索。不幸的是,Firefox不支持。若是腳本能異步,那麼也就能夠移動到底部。

5.2 Make JavaScript and CSS External

使用外部JS和CSS。

這裏的不少性能規則涉及外部組件怎麼管理。但你首先要明白一個基本問題:JS和CSS是應該包含在外部文件仍是內連在頁面自己?

真實世界中使用外部文件通常會加快頁面,由於JS和CSS文件被瀏覽器緩存了。內連的JS和CSS怎在每次HTML文檔下載時都被下載。內連減小了http請求,但增長了HTML文檔大小。另外一方面,若是JS和CSS被緩存了,那麼HTML文檔能夠減少大小而不增長HTTP請求。

核心因素,就是JS和CSS被緩存相對於HTML文檔被請求的頻率。儘管這個因素很難被量化,但能夠用不一樣的指標來計算。若是網站用戶每一個session有多個pv,許多頁面重用相同的JS和CSS,那麼有很大可能用外部JS和CSS更好。

許多網站用這些指標計算後在中間位置。對這些網站來講,最佳方案仍是用外部JS和CSS文件。惟一例外是內連更被主頁偏心,如http://www.yahoo.com/。主頁每一個session可能只有少許的甚至一個pv,這時候內連可能更快。

對多個頁面的首頁來講,能夠經過技術減小(其它頁面的)http請求。在首頁用內連,初始化後動態加載外部文件,接下來的頁面若是用到這些文件,就可使用緩存了。

5.3 Minify JavaScript and CSS

壓縮JS和CSS。

壓縮就是刪除代碼中沒必要要的字符來減少文件大小,從而提升加載速度。當代碼壓縮時,註釋刪除,不須要的空格(空白,換行,tab)也被刪除。

混淆是對代碼可選的優化。它比壓縮更復雜,而且可能產生bug。在對美國top10網站的調查,壓縮可減少21%,而混淆可減少25%。

除了外部腳本和樣式,內連的腳本和樣式一樣應該被壓縮。

5.4 Remove Duplicate Scripts

刪除重複的腳本。

在頁面中引入相同的腳本兩次會傷害性能。可能超出你的預料,美國top10網站的2家有重複腳本引入。兩個主要因素形成同一頁面引入相同腳本:團隊大小和腳本數量。當確實引入重複腳本,會發出沒必要要的http請求和浪費js執行時間。

發出沒必要要的http請求發生在IE而不是Firefox。在IE,若是外部腳本引入兩次且沒有緩存,它會發出2個請求。即便腳本被緩存,刷新時也會發出額外請求。

除了增長http請求,時間被浪費在執行腳本屢次上。無論IE仍是Firefox都會執行屢次。

一種避免屢次引入腳本的方法是在模板系統實現一個腳本管理模塊。

5.5 Minimize DOM Access

最小化DOM訪問。

用JS訪問DOM元素是緩慢的,因此爲了響應更好的頁面,你應該:

  • 緩存訪問過的元素的引用
  • 在DOM樹外更新節點,而後添加到DOM樹
  • 避免用JS實現固定佈局

5.6 Develop Smart Event Handlers

開發聰明的事件處理

有時候頁面看起來不那麼響應(響應速度慢),是由於綁定到不一樣元素的大量事件處理函數執行太屢次。這是爲何使用_事件委託_是一種好方法。

另外,你沒必要等到onload事件來開始處理DOM樹,DOMContentLoaded更快。大多時候你須要的只是想訪問的元素已在DOM樹中,因此你沒必要等到全部圖片被下載。

6 Images

6.1 Optimize Images

優化圖片

在設計師建好圖片後,在上傳圖片到服務器前你仍能夠作些事:

  • 檢查gif圖片的調色板大小是否匹配圖片顏色數。
  • 能夠把gif轉成png看看有沒有變小。除了動畫,gif通常能夠轉成png8。
  • 運行pngcrush或其它工具壓縮png。
  • 運行jpegtran或其它工具壓縮jpeg。

6.2 Optimize CSS Sprites

優化CSS雪碧圖

  • 把圖片橫向合併而不是縱向,橫向更小。
  • 把顏色近似的圖片合併到一張雪碧圖,這樣可讓顏色數更少,若是低於256就能夠用png8.
  • "Be mobile-friendly"而且合併時圖片間的間距不要太大。這對圖片大小影響不是太大,但客戶端解壓時須要的內存更少。100×100是10000個像素,1000×1000是1000000個像素。

6.3 Don't Scale Images in HTML

不要在html中縮放圖片

不要由於你能夠設置圖片的寬高就去用比你須要的大得多的圖片。若是你須要

<img width="100" height="100" src="mycat.jpg" alt="My Cat" /> 

那麼,就用100x100px的圖片,而不是500x500px的。

6.4 Make favicon.ico Small and Cacheable

favicon.ico小且緩存

favicon.ico是在你服務器根路徑的圖片。邪惡的是即便你不關心它,瀏覽器仍然會請求它。因此最好不要響應404。另外因爲在同一服務器,每次請求favicon.ico時也會帶上cookie。這個圖片還會影響下載順序,好比在IE,若是你在onload時下載額外的組件,fcvicon會在這些組件以前被下載。

怎麼減輕favicon.ico的缺點?

  • 小,最好1K如下
  • 設置Expires頭部。也許能夠安全地設置爲幾個月。

7 Mobile

7.1 Keep Components under 25K

保持組件小於25K

這個限制與iPhone不緩存大於25K的組件相關。注意,這是非壓縮(uncompressed)的文件大小。在這裏minification(壓縮,不要與compress混淆)很重要,由於gzip沒法知足(iPhone)。

7.2 Pack Components into a Multipart Document

打包組件到一個多部父文檔

打包組件到一個多部父文檔相似於帶附件的郵件。它幫助你在一個http請求中獲取多個組件,但注意,iPhone不支持。

 

 

具體的關於優化的知識點或問題

1. 爲何網頁設置緩存後仍然有請求(304響應)?

瀏覽器刷新是conditional request,因此若是經過刷新來看緩存是否有效確定是304。能夠試試輸入網址按回車或者回退鍵來看效果。另外因爲HTML文檔不多設置徹底緩存(通常要和服務器驗證),能夠看靜態組件的緩存效果(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(無樣式內容閃爍)

Flash of unstyled content(FOUC)就是在加載外部樣式表以前,瀏覽器按默認樣式顯示了內容,這是由於瀏覽器在全部資源都下載好前就開始渲染頁面了。一旦外部樣式被加載,瀏覽器就會修正樣式,但這種修正多是可見的,也就是FOUC。

怎麼避免?在<head>中經過<link>引入樣式,避免使用@import

相關文章
相關標籤/搜索