DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> WEB網站前端 >> WEB前端代碼 >> 如何優化網站性能,提高頁面加載速度
如何優化網站性能,提高頁面加載速度
編輯:WEB前端代碼     

前言: 

在同樣的網絡環境下,兩個同樣能滿足你的需求的網站,一個“Duang”的一下就加載出來了,一個糾結了半天才出來,你會選擇哪個?研究表明:用戶最滿意的打開網頁時間是2-5秒,如果等待超過10秒,99%的用戶會關閉這個網頁。也許這樣講,各位還不會有太多感觸,接下來我列舉一組數據:Google網站訪問速度每慢400ms就導致用戶搜索請 求下降0.59%;Amazon每增加100ms網站延遲將導致收入下降1%;雅虎如果有400ms延遲會導致流量下降5-9%。網站的加載速度嚴重影響了用戶體驗,也決定了這個網站的生死存亡。

可能有人會說:網站的性能是後端工程師的事情,與前端並無多大關系。我只能說,too young too simple。事實上,只有10%~20%的最終用戶響應時間是用在從Web服務器獲取HTML文檔並傳送到浏覽器的,那剩余的時間去哪兒了?來瞄一下性能黃金法則

只有10%~20%的最終用戶響應時間花在了下載HTML文檔上。其余的80%~90%時間花在了下載頁面中的所有組件上。

接下來我們將研究一下前端攻城獅如何來提高頁面的加載速度。

 

一、減少HTTP請求

上面說到80%~90%時間花在了下載頁面中的所有組件進行的HTTP請求上。因此,改善響應時間最簡單的途徑就是減少HTTP請求的數量。

圖片地圖:

假設導航欄上有五幅圖片,點擊每張圖片都會進入一個鏈接,這樣五張導航的圖片在加載時會產生5個HTTP請求。然而,使用一個圖片地圖可以提高效率,這樣就只需要一個HTTP請求。

服務器端圖片地圖:將所有點擊提交到同一個url,同時提交用戶點擊的x、y坐標,服務器端根據坐標映射響應

客戶端圖片地圖:直接將點擊映射到操作

<img src="planets.jpg" border="0" usemap="#planetmap" alt="Planets" />

<map name="planetmap" id="planetmap">
     <area shape="rect" coords="180,139,14" href ="venus.html" alt="Venus" />
     <area shape="rect" coords="129,161,10" href ="mercur.html" alt="Mercury" />
     <area shape="rect" coords="0,0,110,260" href ="sun.html" alt="Sun" />
     <area shape="rect" coords="140,0,110,260" href ="star.html" alt="Sun" />
</map>

使用圖片地圖的缺點:指定坐標區域時,矩形或圓形比較容易指定,而其它形狀手工指定比較難

CSS Sprites

CSS Sprites直譯過來就是CSS精靈,但是這種翻譯顯然是不夠的,其實就是通過將多個圖片融合到一副圖裡面,然後通過CSS的一些技術布局到網頁上。特別是圖片特別多的網站,如果能用css sprites降低圖片數量,帶來的將是速度的提升。

<div>
    <span id="image1" class="nav"></span>
    <span id="image2" class="nav"></span>
    <span id="image3" class="nav"></span>
    <span id="image4" class="nav"></span>
    <span id="image5" class="nav"></span>
</div>
.nav {
    width: 50px;
    height: 50px;
    display: inline-block;
    border: 1px solid #000;
    background-image: url('E:/1.png');
}
#image1 {
        background-position: 0 0;
}
#image2 {
        background-position: -95px 0;
}
#image3 {
        background-position: -185px 0;
}
#image4 {
        background-position: -275px 0;
}
#image5 {
        background-position: -366px -3px;
}

運行結果:

PS:使用CSS Sprites還有可能降低下載量,可能大家會認為合並後的圖片會比分離圖片的總和要大,因為還有可能會附加空白區域。實際上,合並後的圖片會比分離的圖片總和要小,因為它降低了圖片自身的開銷,譬如顏色表、格式信息等。

字體圖標

在可以大量使用字體圖標的地方我們可以盡可能使用字體圖標,字體圖標可以減少很多圖片的使用,從而減少http請求,字體圖標還可以通過CSS來設置顏色、大小等樣式,何樂而不為。

合並腳本 和樣式表

將多個樣式表或者腳本文件合並到一個文件中,可以減少HTTP請求的數量從而縮短效應時間。

然而合並所有文件對許多人尤其是編寫模塊化代碼的人來說是不能忍的,而且合並所有的樣式文件或者腳本文件可能會導致在一個頁面加載時加載了多於自己所需要的樣式或者腳本,對於只訪問該網站一個(或幾個)頁面的人來說反而增加了下載量,所以大家應該自己權衡利弊。

 

二、使用CDN

如果應用程序web服務器離用戶更近,那麼一個HTTP請求的響應時間將縮短。另一方面,如果組件web服務器離用戶更近,則多個HTTP請求的響應時間將縮短。

 CDN(內容發布網絡)是一組分布在多個不同地理位置的Web服務器,用於更加有效地向用戶發布內容。在優化性能時,向特定用戶發布內容的服務器的選擇基於對網絡慕課擁堵的測量。例如,CDN可能選擇網絡階躍數最小的服務器,或者具有最短響應時間的服務器。

CDN還可以進行數據備份、擴展存儲能力,進行緩存,同時有助於緩和Web流量峰值壓力。

CDN的缺點:

1、響應時間可能會受到其他網站流量的影響。CDN服務提供商在其所有客戶之間共享Web服務器組。

2、如果CDN服務質量下降了,那麼你的工作質量也將下降

3、無法直接控制組件服務器

 

三、添加Expires頭

頁面的初次訪問者會進行很多HTTP請求,但是通過使用一個長久的Expires頭,可以使這些組件被緩存,下次訪問的時候,就可以減少不必要的HTPP請求,從而提高加載速度。

Web服務器通過Expires頭告訴客戶端可以使用一個組件的當前副本,直到指定的時間為止。例如:

Expires: Fri, 18 Mar 2016 07:41:53 GMT

Expires缺點: 它要求服務器和客戶端時鐘嚴格同步;過期日期需要經常檢查

HTTP1.1中引入Cache-Control來克服Expires頭的限制,使用max-age指定組件被緩存多久。

Cache-Control: max-age=12345600

若同時制定Cache-Control和Expires,則max-age將覆蓋Expires頭

 

四、壓縮組件

從HTTP1.1開始,Web客戶端可以通過HTTP請求中的Accept-Encoding頭來表示對壓縮的支持

Accept-Encoding: gzip,deflate

如果Web服務器看到請求中有這個頭,就會使用客戶端列出來的方法中的一種來進行壓縮。Web服務器通過響應中的Content-Encoding來通知 Web客戶端。

Content-Encoding: gzip

代理緩存

當浏覽器通過代理來發送請求時,情況會不一樣。假設針對某個URL發送到代理的第一個請求來自於一個不支持gzip的浏覽器。這是代理的第一個請求,緩存為空。代理將請求轉發給服務器。此時響應是未壓縮的,代理緩存同時發送給浏覽器。現在,假設到達代理的請求是同一個url,來自於一個支持gzip的浏覽器。代理會使用緩存中未壓縮的內容進行響應,從而失去了壓縮的機會。相反,如果第一個浏覽器支持gzip,第二個不支持,你們代理緩存中的壓縮版本將會提供給後續的浏覽器,而不管它們是否支持gzip。

解決辦法:在web服務器的響應中添加vary頭Web服務器可以告訴代理根據一個或多個請求頭來改變緩存的響應。因為壓縮的決定是基於Accept-Encoding請求頭的,因此需要在vary響應頭中包含Accept-Encoding。

vary: Accept-Encoding  

五、將樣式表放在頭部

 首先說明一下,將樣式表放在頭部對於實際頁面加載的時間並不能造成太大影響,但是這會減少頁面首屏出現的時間,使頁面內容逐步呈現,改善用戶體驗,防止“白屏”。

我們總是希望了裡卻能夠盡快顯示內容,為用戶提供可視化的回饋,這對網速慢的用戶來說是很重要的。

將樣式表放在文檔底部會阻止浏覽器中的內容逐步出現。為了避免當樣式變化時重繪頁面元素,浏覽器會阻塞內容逐步呈現,造成“白屏”。這源自浏覽器的行為:如果樣式表仍在加載,構建呈現樹就是一種浪費,因為所有樣式表加載解析完畢之前務虛會之任何東西

 

六、將腳本放在底部

更樣式表相同,腳本放在底部對於實際頁面加載的時間並不能造成太大影響,但是這會減少頁面首屏出現的時間,使頁面內容逐步呈現。

js的下載和執行會阻塞Dom樹的構建(嚴謹地說是中斷了Dom樹的更新),所以script標簽放在首屏范圍內的HTML代碼段裡會截斷首屏的內容。

下載腳本時並行下載是被禁用的——即使使用了不同的主機名,也不會啟用其他的下載。因為腳本可能修改頁面內容,因此浏覽器會等待;另外,也是為了保證腳本能夠按照正確的順序執行,因為後面的腳本可能與前面的腳本存在依賴關系,不按照順序執行可能會產生錯誤。

 

七、避免CSS表達式

CSS表達式是動態設置CSS屬性的一種強大並且危險的方式,它受到了IE5以及之後版本的支持。

p {
    width: expression(func(),document.body.clientWidth > 400 ? "400px" : "auto");
    height: 80px;
    border: 1px solid #f00;
}
<p><span></span></p>
<p><span></span></p>
<p><span></span></p>
<p><span></span></p>
<p><span></span></p>
<script>
    var n = 0;
    function func() {
        n++;
        // alert();
        console.log(n);
    }
</script>

鼠標移動了幾次,函數的運行次數輕而易舉的達到了幾千次,危險性顯而易見。

如何解決:

一次性表達式:

p {
    width: expression(func(this));
    height: 80px;
    border: 1px solid #f00;
}
<p><span></span></p>
<p><span></span></p>
<p><span></span></p>
<p><span></span></p>
<p><span></span></p>
<script>
    var n = 0;
    function func(elem) {
        n++;
        elem.style.width = document.body.clientWidth > 400 ? '400px' : "auto";
        console.log(n);
    }
</script>

事件處理機制

用js事件處理機制來動態改變元素的樣式,使函數運行次數在可控范圍之內。

 

八、使用外部的JavaScript和CSS

內聯腳本或者樣式可以減少HTTP請求,按理來說可以提高頁面加載的速度。然而在實際情況中,當腳本或者樣式是從外部引入的文件,浏覽器就有可能緩存它們,從而在以後加載的時候能夠直接使用緩存,而HTML文檔的大小減小,從而提高加載速度。

影響因素:

1、每個用戶產生的頁面浏覽量越少,內聯腳本和樣式的論據越強勢。譬如一個用戶每個月只訪問你的網站一兩次,那麼這種情況下內聯將會更好。而如果該用戶能夠產生很多頁面浏覽量,那麼緩存的樣式和腳本將會極大減少下載的時間,提交頁面加載速度。

2、如果你的網站不同的頁面之間使用的組件大致相同,那麼使用外部文件可以提高這些組件的重用率。

加載後下載

有時候我們希望內聯樣式和腳本,但又可以為接下來的頁面提供外部文件。那麼我們可以在頁面加載完成止嘔動態加載外部組件,以便用戶接下來的訪問。

   function doOnload() {
       setTimeout("downloadFile()",1000);
   }
   
   window.onload = doOnload;
   
   function downloadFile() {
       downloadCss("http://abc.com/css/a.css");
       downloadJS("http://abc.com/js/a.js");
  }
  
  function downloadCss(url) {
      var ele = document.createElement('link');
      ele.rel = "stylesheet";
      ele.type = "text/css";
      ele.href = url;
  
      document.body.appendChild(ele);
  }
  
  function downloadJS(url) {
      var ele = document.createElement('script');
      ele.src = url;
      document.body.appendChild(ele);
  }

在該頁面中,JavaScript和CSS被加載兩次(內聯和外部)。要使其正常工作,必須處理雙重定義。將這些組件放到一個不可見的IFrame中是一個比較好的解決方式。

 

 九、減少DNS查找

當我們在浏覽器的地址欄輸入網址(譬如: www.hovertree.com) ,然後回車,回車這一瞬間到看到頁面到底發生了什麼呢?

域名解析 --> 發起TCP的3次握手 --> 建立TCP連接後發起http請求 --> 服務器響應http請求,浏覽器得到html代碼 --> 浏覽器解析html代碼,並請求html代碼中的資源(如js、css、圖片等) --> 浏覽器對頁面進行渲染呈現給用戶

域名解析是頁面加載的第一步,那麼域名是如何解析的呢?以Chrome為例:

1.  Chrome浏覽器 會首先搜索浏覽器自身的DNS緩存(緩存時間比較短,大概只有1分鐘,且只能容納1000條緩存),看自身的緩存中是否有www.hovertree.com 對應的條目,而且沒有過期,如果有且沒有過期則解析到此結束。
 注:我們怎麼查看Chrome自身的緩存?可以使用 chrome://net-internals/#dns 來進行查看
 
2.  如果浏覽器自身的緩存裡面沒有找到對應的條目,那麼Chrome會搜索操作系統自身的DNS緩存,如果找到且沒有過期則停止搜索解析到此結束.
 注:怎麼查看操作系統自身的DNS緩存,以Windows系統為例,可以在命令行下使用 ipconfig /displaydns 來進行查看 
  
3.  如果在Windows系統的DNS緩存也沒有找到,那麼嘗試讀取hosts文件(位於C:\Windows\System32\drivers\etc),看看這裡面有沒有該域名對應的IP地址,如果有則解析成功。

4.  如果在hosts文件中也沒有找到對應的條目,浏覽器就會發起一個DNS的系統調用,就會向本地配置的首選DNS服務器(一般是電信運營商提供的,也可以使用像Google提供的DNS服務器)發起域名解析請求(通過的是UDP協議向DNS的53端口發起請求,這個請求是遞歸的請求,也就是運營商的DNS服務器必須得提供給我們該域名的IP地址),運營商的DNS服務器首先查找自身的緩存,找到對應的條目,且沒有過期,則解析成功。如果沒有找到對應的條目,則有運營商的DNS代我們的浏覽器發起迭代DNS解析請求,它首先是會找根域的DNS的IP地址(這個DNS服務器都內置13台根域的DNS的IP地址),找打根域的DNS地址,就會向其發起請求(請問www.hovertree.com這個域名的IP地址是多少啊?),根域發現這是一個頂級域com域的一個域名,於是就告訴運營商的DNS我不知道這個域名的IP地址,但是我知道com域的IP地址,你去找它去,於是運營商的DNS就得到了com域的IP地址,又向com域的IP地址發起了請求(請問www.hovertree.com這個域名的IP地址是多少?),com域這台服務器告訴運營商的DNS我不知道www.hovertree.com這個域名的IP地址,但是我知道hovertree.com這個域的DNS地址,你去找它去,於是運營商的DNS又向hovertree.com這個域名的DNS地址(這個一般就是由域名注冊商提供的,像萬網,新網等)發起請求(請問www.hovertree.com這個域名的IP地址是多少?),這個時候hovertree.com域的DNS服務器一查,诶,果真在我這裡,於是就把找到的結果發送給運營商的DNS服務器,這個時候運營商的DNS服務器就拿到了www.hovertree.com這個域名對應的IP地址,並返回給Windows系統內核,內核又把結果返回給浏覽器,終於浏覽器拿到了www.hovertree.com對應的IP地址,該進行一步的動作了。

注:一般情況下是不會進行以下步驟的

如果經過以上的4個步驟,還沒有解析成功,那麼會進行如下步驟:
5.  操作系統就會查找NetBIOS name Cache(NetBIOS名稱緩存,就存在客戶端電腦中的),那這個緩存有什麼東西呢?凡是最近一段時間內和我成功通訊的計算機的計算機名和Ip地址,就都會存在這個緩存裡面。什麼情況下該步能解析成功呢?就是該名稱正好是幾分鐘前和我成功通信過,那麼這一步就可以成功解析。

6.  如果第5步也沒有成功,那會查詢WINS 服務器(是NETBIOS名稱和IP地址對應的服務器)

7.  如果第6步也沒有查詢成功,那麼客戶端就要進行廣播查找

8.  如果第7步也沒有成功,那麼客戶端就讀取LMHOSTS文件(和HOSTS文件同一個目錄下,寫法也一樣)

如果第八步還沒有解析成功,那麼就宣告這次解析失敗,那就無法跟目標計算機進行通信。只要這八步中有一步可以解析成功,那就可以成功和目標計算機進行通信。

DNS也是開銷,通常浏覽器查找一個給定域名的IP地址要花費20~120毫秒,在完成域名解析之前,浏覽器不能從服務器加載到任何東西。那麼如何減少域名解析時間,加快頁面加載速度呢?

當客戶端DNS緩存(浏覽器和操作系統)緩存為空時,DNS查找的數量與要加載的Web頁面中唯一主機名的數量相同,包括頁面URL、腳本、樣式表、圖片、Flash對象等的主機名。減少主機名的 數量就可以減少DNS查找的數量。

減少唯一主機名的數量會潛在減少頁面中並行下載的數量(HTTP 1.1規范建議從每個主機名並行下載兩個組件,但實際上可以多個),這樣減少主機名和並行下載的方案會產生矛盾,需要大家自己權衡。建議將組件放到至少兩個但不多於4個主機名下,減少DNS查找的同時也允許高度並行下載。

 

十、精簡JavaScript

精簡

精簡就是從代碼中移除不必要的字符以減少文件大小,降低加載的時間。代碼精簡的時候會移除不必要的空白字符(空格,換行、制表符),這樣整個文件的大小就變小了。

混淆

混淆是應用在源代碼上的另外一種方式,它會移除注釋和空白符,同時它還會改寫代碼。在混淆的時候,函數和變量名將會被轉換成更短的字符串,這時代碼會更加精煉同時難以閱讀。通常這樣做是為了增加對代碼進行反向工程的難度,這也同時提高了性能。

缺點:

混淆本身比較復雜,可能會引入錯誤。

需要對不能改變的符號做標記,防止JavaScript符號(譬如關鍵字、保留字)被修改。

混淆會使代碼難以閱讀,這使得在產品環境中調試問題更加困難。

在以上提到了關於用gzip之類的壓縮方式來壓縮文件,這邊說明一下,就算使用gzip等方式來壓縮文件,精簡代碼依然是有必要的。一般來說,壓縮產生的節省是高於精簡的,在生產環境中,精簡和壓縮同時使用能夠最大限度的獲得更多的節省。

CSS的精簡

CSS的精簡帶來的節省一般來說是小於JavaScript精簡的,因為CSS中注釋和空白相對較少。

除了移除空白、注釋之外,CSS可以通過優化來獲得更多的節省:

合並相同的類;

移除不使用的類;

使用縮寫,譬如

.right {
    color: #fff;

    padding-top: 0; 

    margin: 0 10px;
    
    border: 1px solid #111
}
.wrong {
    color: #ffffff;

    padding-top: 0px; 

    margin-top: 0;
    margin-bottom: 0;
    margin-left: 10px;
    margin-right: 10px;


    border-color: #111;
    border-width: 1px;
    border-style: solid;
}

上面.right是正確的的寫法,顏色使用縮寫,使用0代替0px,合並可以合並的樣式。另外,在精簡的時候其實樣式最後一行的';'也是可以省略的。

來看看精簡的例子:

以上分別是jquery-2.0.3的學習版(未精簡)和精簡版,可見精簡文件的大小比源文件小了155k,而且,在精簡版中jquery還做了混淆,譬如用e代替window等,從而獲得最大的節省。

 

十一、避免重定向

什麼是重定向?

重定向用於將用戶從一個URL重新路由到另一個URL。

常用重定向的類型

301:永久重定向,主要用於當網站的域名發生變更之後,告訴搜索引擎域名已經變更了,應該把舊域名的的數據和鏈接數轉移到新域名下,從而不會讓網站的排名因域名變更而受到影響。

302:臨時重定向,主要實現post請求後告知浏覽器轉移到新的URL。

304:Not Modified,主要用於當浏覽器在其緩存中保留了組件的一個副本,同時組件已經過期了,這是浏覽器就會生成一個條件GET請求,如果服務器的組件並沒有修改過,則會返回304狀態碼,同時不攜帶主體,告知浏覽器可以重用這個副本,減少響應大小。

重定向如何損傷性能?

當頁面發生了重定向,就會延遲整個HTML文檔的傳輸。在HTML文檔到達之前,頁面中不會呈現任何東西,也沒有任何組件會被下載。

來看一個實際例子:對於ASP.NET webform開發來說,對於新手很容易犯一個錯誤,就是把頁面的連接寫成服務器控件後台代碼裡,例如用一個Button控件,在它的後台click事件中寫上:Response.Redirect("");然而這個Button的作用只是轉移URL,這是非常低效的做法,因為點擊Button後,先發送一個Post請求給服務器,服務器處理Response.Redirect("")後就發送一個302響應給浏覽器,浏覽器再根據響應的URL發送GET請求。正確的做法應該是在html頁面直接使用a標簽做鏈接,這樣就避免了多余的post和重定向。

重定向的應用場景

1. 跟蹤內部流量

重定向經常用於跟蹤用戶流量的方向,當擁有一個門戶主頁的時候,同時想對用戶離開主頁後的流量進行跟蹤,這時可以使用重定向。例如: 某網站主頁新聞的鏈接地址http://a.com/r/news,點擊該鏈接將產生301響應,其Location被設置為http://news.a.com。通過分析a.com的web服務器日志可以得知人們離開首頁之後的去向。

我們知道重定向是如何損傷性能的,為了實現更好的效率,可以使用Referer日志來跟蹤內部流量去向。每個HTTP請求都有一個Referer表示原始請求頁(除了從書簽打開或直接鍵入URL等操作),記錄下每個請求的Referer,就避免了向用戶發送重定向,從而改善了響應時間。

2. 跟蹤出站流量

有時鏈接可能將用戶帶離你的網站,在這種情況下,使用Referer就不太現實了。

同樣也可以使用重定向來解決跟蹤出站流量問題。以百度搜索為例,百度通過將每個鏈接包裝到一個302重定向來解決跟蹤的問題,例如搜索關鍵字“前端性能優化”,搜索結果中的一個URL為https://www.baidu.com/link?url=I884O5FlH9bWqENe0sceYR2qTSB05BQEcFYT8_Ga8tr01ZiyADnmj4rIFEdA4nTnAfCGBlfTZYNVrA7qVIMRqq&wd=&eqid=ec6e824500000ef600000003580068e1,即使搜索結果並沒有變,但這個字符串是動態改變的,暫時還不知道這裡起到怎樣的作用?(個人感覺:字符串中包含了待訪問的網址,點擊之後會產生302重定向,將頁面轉到目標頁面(待修改,求大神們給我指正))

除了重定向外,我們還可以選擇使用信標(beacon)——一個HTTP請求,其URL中包含有跟蹤信息。跟蹤信息可以從信標Web服務器的訪問日記中提取出來,信標通常是一個1px*1px的透明圖片,不過204響應更優秀,因為它更小,從來不被緩存,而且絕不會改變浏覽器的狀態。

 

十二、刪除重復腳本

在團隊開發一個項目時,由於不同開發者之間都可能會向頁面中添加頁面或組件,因此可能相同的腳本會被添加多次。

重復的腳本會造成不必要的HTTP請求(如果沒有緩存該腳本的話),並且執行多余的JavaScript浪費時間,還有可能造成錯誤。

如何避免重復腳本呢?

1. 形成良好的腳本組織。重復腳本有可能出現在不同的腳本包含同一段腳本的情況,有些是必要的,但有些卻不是必要的,所以需要對腳本進行一個良好的組織。

2. 實現腳本管理器模塊。

例如:

  function insertScript($file) {
      if(hadInserted($file)) {
           return;
       }
       exeInsert($file);
   
       if(hasDependencies($file)) {
   
           $deps = getDependencies($file);
  
          foreach ($deps as $script) {
              insertScript($script);
          }
  
          echo "<script type='text/javascript' src='".getVersion($file)."'></script>";
  
      }
  }

先檢查是否插入過,如果插入過則返回。如果該腳本依賴其它腳本,則被依賴的腳本也會被插入。最後腳本被傳送到頁面,getVersion會檢查腳本並返回追加了對應版本號的文件名,這樣如果腳本的版本變化了,那麼以前浏覽器緩存的就會失效。

 

十三、配置ETag

以前浏覽器緩存的就會失效。

什麼是ETag?

實體標簽(EntityTag)是唯一標識了一個組件的一個特定版本的字符串,是web服務器用於確認緩存組件的有效性的一種機制,通常可以使用組件的某些屬性來構造它。

條件GET請求

如果組件過期了,浏覽器在重用它之前必須首先檢查它是否有效。浏覽器將發送一個條件GET請求到服務器,服務器判斷緩存還有效,則發送一個304響應,告訴浏覽器可以重用緩存組件。

那麼服務器是根據什麼判斷緩存是否還有效呢?有兩種方式:

ETag(實體標簽);

最新修改日期;

最新修改日期

原始服務器通過Last-Modified響應頭來返回組件的最新修改日期。

舉個栗子:

當我們不帶緩存訪問www.google.com.hk的時候,我們需要下載google的logo,這時會發送這樣一個HTTP請求:

Request:

GET googlelogo_color_272x92dp.png HTTP 1.1

Host: www.google.com.hk

Response:

HTTP 1.1 200 OK

Last-Modified:Fri, 04 Sep 2015 22:33:08 GMT

當需要再次訪問相同組件的時候,同時緩存已經過期,浏覽器會發送如下條件GET請求:

Request:

GET googlelogo_color_272x92dp.png HTTP 1.1

If-Modified-Since:Fri, 04 Sep 2015 22:33:08 GMT

Host: www.google.com.hk

Response:

HTTP 1.1 304 Not Modified

體標簽

ETag提供了另外一種方式,用於檢測浏覽器緩存中的組件與原始服務器上的組件是否匹配。摘抄自書上的例子:

不帶緩存的請求:

Request:

GET /i/yahoo/gif HTTP 1.1

Host: us.yimg.com

Response:

HTTP 1.1 200 OK

Last-Modified:Tue,12 Dec 200603:03:59 GMT

ETag:”10c24bc-4ab-457elc1f“

再次請求相同組件:

Request:

GET /i/yahoo/gif HTTP 1.1

Host: us.yimg.com

If-Modified-Since:Tue,12 Dec 200603:03:59 GMT

If-None-Match:”10c24bc-4ab-457elc1f“

Response:

HTTP 1.1 304 Not Midified

為什麼要引入ETag?

ETag主要是為了解決Last-Modified無法解決的一些問題:

1. 一些文件也許會周期性的更改,但是他的內容並不改變(僅僅改變的修改時間),這個時候我們並不希望客戶端認為這個文件被修改了,而重新GET;

2. 某些文件修改非常頻繁,比如在秒以下的時間內進行修改,(比方說1s內修改了N次),If-Modified-Since能檢查到的粒度是s級的,這種修改無法判斷(或者說UNIX記錄MTIME只能精確到秒);

3. 某些服務器不能精確的得到文件的最後修改時間。

ETag帶來的問題

ETag的問題在於通常使用某些屬性來構造它,有些屬性對於特定的部署了網站的服務器來說是唯一的。當使用集群服務器的時候,浏覽器從一台服務器上獲取了原始組件,之後又向另外一台不同的服務器發起條件GET請求,ETag就會出現不匹配的狀況。例如:使用inode-size-timestamp來生成ETag,文件系統使用inode存儲文件類型、所有者、組和訪問模式等信息,在多台服務器上,就算文件大小、權限、時間戳等都相同,inode也是不同的。

最佳實踐

1. 如果使用Last-Modified不會出現任何問題,可以直接移除ETag,google的搜索首頁則沒有使用ETag。

2. 確定要使用ETag,在配置ETag的值的時候,移除可能影響到組件集群服務器驗證的屬性,例如使用size-timestamp來生成時間戳。

 

十四、使Ajax可緩存

維基百科中這樣定義Ajax:

AJAX即“Asynchronous JavaScript and XML”(異步的JavaScript與XML技術),指的是一套綜合了多項技術的浏覽器端網頁開發技術。Ajax的概念由傑西·詹姆士·賈瑞特所提出。

傳統的Web應用允許用戶端填寫表單(form),當提交表單時就向Web服務器發送一個請求。服務器接收並處理傳來的表單,然後送回一個新的網頁,但這個做法浪費了許多帶寬,因為在前後兩個頁面中的大部分HTML碼往往是相同的。由於每次應用的溝通都需要向服務器發送請求,應用的回應時間依賴於服務器的回應時間。這導致了用戶界面的回應比本機應用慢得多。

與此不同,AJAX應用可以僅向服務器發送並取回必須的數據,並在客戶端采用JavaScript處理來自服務器的回應。因為在服務器和浏覽器之間交換的數據大量減少(大約只有原來的5%)[來源請求],服務器回應更快了。同時,很多的處理工作可以在發出請求的客戶端機器上完成,因此Web服務器的負荷也減少了。

類似於DHTML或LAMP,AJAX不是指一種單一的技術,而是有機地利用了一系列相關的技術。雖然其名稱包含XML,但實際上數據格式可以由JSON代替,進一步減少數據量,形成所謂的AJAJ。而客戶端與服務器也並不需要異步。一些基於AJAX的“派生/合成”式(derivative/composite)的技術也正在出現,如AFLAX。

Ajax的目地是為突破web本質的開始—停止交互方式,向用戶顯示一個白屏後重繪整個頁面不是一種好的用戶體驗。

異步與即時

Ajax的一個明顯的有點就是向用戶提供了即時反饋,因為它異步的從後端web服務器請求信息。

用戶是否需要等待的關鍵因素在於Ajax請求是被動的還是主動的。被動請求是為了將來來使用而預先發起的,主動請求是基於用戶當前的操作而發起的

什麼樣的AJAX請求可以被緩存?

POST的請求,是不可以在客戶端緩存的,每次請求都需要發送給服務器進行處理,每次都會返回狀態碼200。(可以在服務器端對數據進行緩存,以便提高處理速度)

GET的請求,是可以(而且默認)在客戶端進行緩存的,除非指定了不同的地址,否則同一個地址的AJAX請求,不會重復在服務器執行,而是返回304。

Ajax請求使用緩存

在進行Ajax請求的時候,可以選擇盡量使用get方法,這樣可以使用客戶端的緩存,提高請求速度。

 

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

 

 

 

 

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved