《高性能網站建設指南》筆記

 

規則1:減小HTTP請求

        1. 圖片地圖(map)javascript

        2. CSS Spritesphp

        3. 內聯圖片  data:[<mediatype>][;base64],<data>css

        4. 合併腳本和樣式表html

規則2:使用內容發佈網絡(CDN)

規則3:添加Expires頭

        更新方法:修改連接/組件文件名(好比設置版本號)java

規則4:壓縮組件(gzip)

規則5:將樣式表放在頂部(使用link標籤將樣式表放在文檔head中)

規則6:將腳本放在底部

規則7:避免CSS表達式

        (IE:expression【推薦一次性表達式/事件處理器】)web

規則8:使用外部JavaScript和CSS

規則9:減小DNS查找

        經過keep-alive和較少的域名來減小DNS查找數據庫

規則10:精簡JavaScript (精簡、混淆)

規則11:避免重定向

規則12:  刪除重複腳本

規則13:配置ETag(配置或移除ETag)

規則14:使Ajax可緩存

 


 

緒言A:


 

  至少有80%的時間花在了顯示Web頁面上,而且這些時間是花在html文檔下載完畢後發生的。express

 

14條規則:


 

 

規則1: 減小http請求


 

  方法:編程

    1. 圖片地圖(Image Map):在一個圖片上關聯多個url,目標url的選擇取決於用戶點擊了圖片上的哪一個位置。後端

      圖片地圖有兩種類型:服務器端圖片地圖(將全部點擊提交到同一個目標url,向其傳遞用戶點擊的x,y座標。Web應用程序將該x,y座標映射爲適當的操做)和客戶端圖片地圖(將用戶的點擊映射到一個操做)。映射經過html的map標籤實現。

      缺點:在定義圖片地圖上的區域座標時,若是採用手工的方式則很難完成且容易出錯,並且除了矩形意外沒法定義其餘星座。經過dhtml建立的圖片地圖則在ie中沒法工做。

    2. CSS Sprites

      也能夠合併圖片,但更爲靈活。

      方法:使用同一個背景圖片,然而每一個元素有一個不一樣的類,經過background-position屬性指定了CSS Sprites的偏移量:

 1 <style type="text/css">
 2     #navbar span {
 3         width: 31px;
 4         height: 31px;
 5         display: inline;
 6         float:left;
 7         background-image: url(/img/sprite.gif);
 8     }
 9     .home {background-position: 0 0; margin-right: 4px; margin-left: 4px;}
10     .gifts {background-position: -32px 0; margin-right: 4px;}
11     .cart {background-position: -64px 0; margin-right: 4px;}
12     .settings {background-position: -96px 0; margin-right: 4px;}
13     .help {background-position: -128px 0; margin-right: 0;}
14 </style>
15 
16 <div id="navbar" style="background-color: #F4F5EB; border: 2px ridge #333; width:180px; height: 32px; padding: 4px 0 4px 0">
17     <a href="javascript:alert('Home')"><span class="home"></span></a>
18     <a href="javascript:alert('Gifts')"><span class="gifts"></span></a>
19     <a href="javascript:alert('Cart')"><span class="cart"></span></a>
20     <a href="javascript:alert('Settings')"><span class="settings"></span></a>
21     <a href="javascript:alert('Help')"><span class="help"></span></a>
22 </div>

      CSS Sprites還能夠經過合併圖片減小http請求,還下降了下載量。雖然會有人任務合併後的圖片會比分離的圖片總和要大,由於合併的圖片中包含有附加的空白區域。實際上,合併後的圖片會比分離的圖片總和要小,由於它下降了圖片自身的開銷(顏色表,格式信息等)

    3. 內聯圖片

      data:[<mediatype>][;base64],<data>

      經過使用data:URL模式能夠在Web頁面中包含圖片但無需任何額外的http請求。IE還不支持。同時可能存在數據大小上的限制。

      因爲data:URL是內聯在頁面中的,在跨越不一樣頁面時不會被緩存,因此不要去內聯公司logo

    4. 合併腳本和樣式表

 

規則2: 使用內容發佈網絡(CDN,Content Delivery Network)


 

  若是應用程序Web服務器離用戶更近,則一個http請求的響應時間將縮短。另外一方面,若是組件Web服務器離用戶更近,則多個http請求的響應時間將縮短。

  概念:

    CDN是一組分佈在多個不一樣地理位置的Web服務器,用於更加有效地向用戶發佈內容。

  優勢:

    1) 可縮短響應時間

    2) 有助於緩和Web流量峯值壓力

  缺點:

    1) 響應時間可能會受到其餘網站的影響。由於CDN服務提供商在其全部客戶之間共享Web服務器組。

    2) 沒法直接控制組件服務器所帶來的特殊麻煩。

  CDN用於發佈靜態內容,好比圖片、腳本、樣式表和Flash。提供動態html頁面會引入特殊的存儲需求-----數據庫鏈接,狀態管理,驗證,硬件和OS優化等。這些複雜性超過了CDN的能力範圍。另外一方面,靜態文件更容易存儲並具備較少的依賴性。

 

規則3: 添加Expires頭 


 

  【Expires: Thu,15 Apr 2010 20:00:00 GMT】

  做用: 

    Web服務器使用Expires頭來告訴Web客戶端它可使用一個組件的當前副本,直到指定的時間 爲止。HTTP規範中簡要的稱該頭爲「在這一日期/時間以後,響應將被認爲是無效的」。它在HTTP響應中發送。
    若是頁面中的一個圖片返回了這個頭,瀏覽器在後續的頁面瀏覽中會使用緩存的圖片,將HTTP請求的數量減小一個。
 
   缺點:
    Expires頭使用一個特定的時間,它 要求服務器和客戶端的時鐘嚴格同步
    另外,過時日期須要常常檢查,而且一旦將來這一天到來了,還須要在服務器配置中 提供一個新的日期
 
   另外一種選擇:Cache-Control:  【Cache-Control:max-age=315360000】
    Cache-Control能夠克服Expires頭的限制。
    Cache-Control使用max-age指令指定組件被緩存多久。它以秒爲單位定義了一個更新窗。
 
   更新的方法:
    Expires頭會使瀏覽器直接從硬盤上讀取組件而無需生成任何新的http流量。所以,即便在服務器上更新了組件,已經訪問過網站的用戶也不大可能獲取新的組件。爲了確保用戶能獲取組件的最新版本,須要在全部html頁面中 修改組件的文件名
    最有效的解決方案是修改其全部連接,這樣,全新的請求將從原始服務器下載最新的內容。
    好比能夠經過嵌入版本號
 

規則4: 壓縮組件


 

   如何壓縮:
    Web客戶端能夠經過http請求中的 Accept-Encoding頭來表示對壓縮的支持:
      Accept-Encoding: gzip,deflate
    若是web服務器在請求信息中看到這個頭信息,它就能夠經過響應的 Content-Encoding頭信息來返回服務器可用的壓縮方式。
      Content-Encoding: gzip
 
   壓縮什麼:
    基於文本的資源如html,js,css,xml都適用於壓縮。然而對於圖片而言,卻不該該對圖片進行壓縮,由於圖片自己是已經被壓縮過了,若是再進行gzip壓縮,有可能獲得的結果是和圖片自己大小相差不大或更大,這樣就浪費了服務器的CPU資源來作無用功了。
 
   優缺點:
    優勢:壓縮組件能夠減小Http響應時間,提高傳輸效率。
    缺點:服務器要經過花費額外的CPU週期來完成壓縮,客戶端要對壓縮文件進行解壓縮。
 
   代理緩存的問題
    瀏覽器直接與服務器通訊時,基於Accept-Encoding 均可以很好地工做。
    但若是經過代理:

      代理緩存服務器是一箇中間層,位於客戶端和服務器之間。使用代理緩存的狀況下,瀏覽器將不直接與服務器通訊,而是經過代理髮送請求。這種狀況下,壓縮就要考慮額外的東西了。

      首先,假設到達代理的是一個來自不支持gzip的瀏覽器的請求,代理會將請求轉發到web服務器,此時web服務器的響應是未通過壓縮的,這個響應會把代理服務器緩存起來併發給瀏覽器。如今,假設到達代理的第二個請求來自一個支持gzip瀏覽器,請求的是與以前相同的URL,代理會直接使用未經壓縮的緩存響應,那麼久失去了進行壓縮的機會了。考慮更糟糕的狀況,第一個請求來自支持gzip的瀏覽器,第二個請求來自不支持gzip的瀏覽器,這樣第二個請求獲得的緩存響應將沒法被解碼,致使出錯。

      解決這一問題的方法就是在Web服務器的響應中添加Vary頭,Vary:Accept-Encoding,表示web服務器告訴緩存服務器分別爲每個Accpet-Encoding請求頭緩存。在前面的例子中,代理經過識別Vary頭,對響應緩存不一樣的版本,避免出錯。

    
 

規則5: 將樣式表放在頂部(使用Link標籤將樣式表放在文檔head中)


 

  將樣式表放在文檔底部會致使在瀏覽器中阻止內容逐步呈現。爲避免當樣式變化時重繪頁面中的元素,瀏覽器會阻塞內容逐步呈現。
  兩種方法:
     1. link標籤:
      <link rel="stylesheet" href="style.css">
    2. @import規則:
      <style>    
        @import url("style.css");
      </style>
       @import規則可能會致使白屏,或組件下載時的無序性。
 

規則6: 將腳本放在底部


 

  使用並行下載:要考慮帶寬和CPU速度。使用兩個主機名更好
  腳本阻塞下載:然而, 在下載腳本時不可使用並行下載。這是爲了保證腳本可以按照正確的順序執行。
 

規則7: 避免css表達式


 

  CSS表達式適用於ie5及以後版本的支持。
     background-color: expression( (new Date()).getHours()%2 ? "#B8D4FF" : "#F08A00");  //ie
  其問題在於:
    表達式的求值頻率過高了。它們不止在頁面呈現和大小改變時求值,當頁面滾動、甚至鼠標拖拽都要求值。
  解決方法:
    1. 一次性表達式
    2. 事件處理器
 

規則8: 使用外部JavaSript和CSS


 

  純粹而言,內聯快一些。由於外部示例須要承擔多個http請求帶來的開銷。
  可是!現實中仍是外部文件較快。 由於JS和CSS文件有機會被瀏覽器緩存起來
  
   主要權衡方法:
     頁面瀏覽量:
      每一個用戶產生的頁面瀏覽量越少,則內聯的更好。
    用戶緩存外部組件的可能性——攜帶 完整緩存和空緩存的頁面瀏覽量。
      若是網站本質上能夠爲用戶帶來更高完整緩存率,使用外部文件的收益就更大。若是不大可能產生完整緩存,則內聯是更好選擇。
  
     重用率
      此外,若是網站中每一個頁面都使用了相同的js和css,使用外部文件能夠提供這些組件的重用率,這時候使用外部文件更有優點。因此這時候還要考慮重用度。
  
   一箭雙鵰的方法:
    1) 加載後下載:
      做爲屢次頁面瀏覽量中的第一次的主頁,咱們但願爲主頁內聯Js和CSS,但又能爲全部後續頁面瀏覽量提供外部文件。這能夠經過在主頁加載完成後動態下載外部組件來實現(經過onload事件)。這可以將外部文件放到瀏覽器中的緩存中以便用戶接下來訪問其餘頁面。
    2) 動態內聯:
      若是主頁服務器知道一個組件是否在瀏覽器的緩存中,它能夠在內聯或使用外部文件之間作出最佳的選擇。儘管服務器不能查看瀏覽器緩存中有什麼,但能夠用cookies作指示器。若是cookies不存在,就內聯js和css。若是cookie出現了,則可能外部組件位於瀏覽器的緩存中,並使用了外部文件。
 

規則9: 減小DNS查找(經過使用Keep-Alive和較少的域名來減小DNS查找)


 

   DNS:將主機名映射到IP地址上。 同時,這也是開銷。
 
   減小頁面花在DNS查找上的時間的方法:
     DNS緩存和TTL
      將DNS查找緩存起來。
      影響DNS緩存的因素:
        TTL(Time-to-live, 存活時間):查找返回的DNS記錄中含有這個值,該值告訴客戶端能夠對該記錄緩存多久
     減小DNS查找
      當客戶端的DNS緩存爲空(瀏覽器和操做系統都是)時,DNS查找的數量與Web頁面中惟一主機名的數量相等。這包括url,圖片,腳本文件,樣式表,Flash對象等的主機名。減小惟一主機名的數量就能夠減小DNS查找的數量。
      可是,減小惟一主機名的數量就會潛在地減小頁面中並行下載的數量。避免DNS查找下降了響應時間,單減小並行下載可能會增長時間。
      權衡之策:
        將這些組件分別放到至少2個,但不要超過4個主機名下。
     使用Keep-Alive:經過重用現有鏈接,從而經過避免TCP/IP開銷來減小響應時間。
 

規則10: 精簡JavaScript


 

   精簡(Minification):
    是從代碼中移除沒必要要的字符以減少其大小,進而改善加載時間的實踐。在代碼被精簡後,因此的註釋以及沒必要要的空白字符(空格,換行和製表符)都將被移除。對js而言,這能夠改善響應時間效率,由於須要下載的文件大大減少了。
   混淆(Obfiscation):
    移除註釋和空白,同時還會改寫代碼。做爲改寫的一部分,函數和變量的名字也將會被轉換成更短的字符串,這時的代碼更加精煉,也更難閱讀。一般這樣作的目的是爲了增長對代碼進行反向工程的難度,但這對提升性能而言也有幫助,由於這比精簡更能減少代碼的大小。
    缺陷:
      由於其更爲複雜,混淆過程自己頗有可能會引入錯誤
    維護:
      因爲混淆會改變js符號,所以須要對任何不能改變的符號(好比api函數)進行標記,防止混淆修改它們。
    調試:
      更加困難。
   其餘方法減小js的時間:
    內聯腳本:也應該精簡。
    壓縮和精簡:
    精簡css:
      優化css——合併相同的類,移除不使用的類等。
      移除註釋和空白:好比使用縮寫(「#666」代替「#666666」)和沒必要要的字符串(「0」代替「0px」)
 

規則11: 避免重定向


 

   概念:
    重定向(Redirects)用於將用戶從一個url從新路由到另外一個URL。
    狀態碼:3xx,最經常使用是301和302
   類型:當Web服務器向瀏覽器返回一個重定向時,響應中就會擁有一個範圍在3xx的狀態碼。這表示用戶代理必須執行進一步操做才能完成請求。幾種3xx狀態碼:
1         300     Multiple Choices (基於Content-type)
2         301     Moved Permancently
3         302     Moved Temporarity(亦做Found)
4         303     See Other(對302的說明)
5         304     Not Modified    並不是真的重定向,用來響應條件GET請求,避免下載已經存在於瀏覽器緩存中的數據
6         305     Use Proxy
7         306     (再也不使用)
8         307     Temporary Redirect(對302的說明)

  

  重定向以外的選擇:

    1. 一種重定向的發生狀況:url的結尾必須出現斜線(/)而沒有出現時

        當主機名後缺乏結尾斜線時是不會發生重定向的

    2. 用於:1)將舊url轉移到新url,經過重定向整合代碼庫;2)將一個網站的不一樣部分鏈接起來,以及基於一些條件(瀏覽器類型、用戶帳號類型等)來引導用戶

      替代方法:

        1)Alias, mod_rewrite和DirectorySlash要求除url外還要提交到一個接口(處理器或文件名),可是易於實現

        2)若是兩個後端位於同一臺服務器上,則它們的代碼可能可以本身鏈接。利於,舊的處理器代碼能夠經過編程調用新的處理器代碼

        3)若是域名變了,可使用一個CNAME(一條DNS記錄,用於建立從一個域名指向另外一個域名的別名)讓兩個主機名指向相同的服務器。若是能作到這一點,這裏提到的技術(Alias、mod_rewrite、DirectorySlash和直接鏈接代碼)就是可行的。

    3. 用於跟蹤內部流量: 重定向經常使用於跟蹤用戶流量的流向。

      替代方法:

        使用Referer日誌來跟蹤流量去向。(內部流量)

    4. 跟蹤出站流量

      替代方法:

        1)使用信標(beacon)

        2)使用XMLHttpRequest

    5. 美化url:使用重定向使得url更加美觀並易於記憶

      使用alias, mod_rewrite, DirectorySlash和直接連接代碼來避免重定向

 

規則12: 刪除重複腳本


 

   解決方法:
    1)在模板系統中實現腳本管理模塊
    2)在php中建立一個稱做insertScript的函數<?php insertScript("menu.js") ?>。 即判斷該腳本是否被包含
  

規則13: 配置ETag


 

   定義:
    實體標籤(Entity Tag, ETag)是Web服務器和瀏覽器用於確認緩存組件有效性的一種機制。
 
   組件如何被緩存和確認?
    1) Expires頭:若是組件沒有過時,那麼它就是新鮮的。這取決於Expires頭的值
    2) 條件get頭:若是緩存的組件過時了(或者用戶明確地從新加載了頁面),瀏覽器在重用以前必須檢查它是否仍然有效。這稱做一個條件GET請求。若是瀏覽器緩存中的組件是有效的,原始服務器不會返回整個組件,而是返回一個「304 Not Modified」狀態碼。
      服務器在檢查緩存的組件是否和原始服務器上的組件匹配時有兩種方法:
        a. 比較最新修改日期: 經過Last-Modified響應頭來返回組件的最新修改日期
        b. 比較實體標籤: (「實體」是「組件」的另外一種稱呼)。ETag是惟一標識了一個組件的一個特定版本的字符串。惟一的格式約束是該字符串必須使用引號引發來。
 
   ETag帶來的問題:
    一般使用組件的某些屬性來構造,這些屬性對於特定的、寄宿了網站的服務器來講是惟一的。當瀏覽器從一臺服務器上獲取了原始組件,以後,又向另外一臺不一樣的服務器發起條件GET請求時,ETag是不會匹配的。
    若是ETag不匹配,用戶就會收到普通的200響應以及組件的全部數據。而對組件進行沒必要要的從新加載還會影響服務器的性能並增長帶寬開銷。
    同時,ETag還下降了代理緩存的效率。
 
   解決方法:
    從ETag中移除changeNumber或徹底移除ETag。
 

規則14: 使Ajax可緩存(確保Ajax請求遵照性能指導,尤爲應具備長久的Expires頭【使響應可緩存】)


 

  1) 優化Ajax請求:
     規則3. 使響應可緩存(最重要)
    規則4. 壓縮組件
    規則9. 減小DNS查找
    規則10. 精簡JS
    規則11. 避免重定向
    規則13. ETag——用仍是不用
相關文章
相關標籤/搜索