web前端效能最佳化

來源:互聯網
上載者:User

標籤:

前言: 

在同樣的網路環境下,兩個同樣能滿足你的需求的網站,一個“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以及之後版本、IE8之前版本的支援。

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、如果你的網站不同的頁面之間使用的組件大致相同,那麼使用外部檔案可以提高這些組件的重用率。

載入後下載

有時候我們希望內聯樣式和指令碼,但又可以為接下來的頁面提供外部檔案。那麼我們可以在頁面載入完成止嘔動態載入外部組件,以便使用者接下來的訪問。

 1   function doOnload() { 2       setTimeout("downloadFile()",1000); 3   } 4    5   window.onload = doOnload; 6    7   function downloadFile() { 8       downloadCss("http://abc.com/css/a.css"); 9       downloadJS("http://abc.com/js/a.js");10  }11  12  function downloadCss(url) {13      var ele = document.createElement(‘link‘);14      ele.rel = "stylesheet";15      ele.type = "text/css";16      ele.href = url;17  18      document.body.appendChild(ele);19  }20  21  function downloadJS(url) {22      var ele = document.createElement(‘script‘);23      ele.src = url;24      document.body.appendChild(ele);25  }

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

 

 九、減少DNS尋找

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

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

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

1.  Chrome瀏覽器 會首先搜尋瀏覽器自身的DNS緩衝(緩衝時間比較短,大概只有1分鐘,且只能容納1000條緩衝),看自身的緩衝中是否有www.linux178.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.linux178.com這個網域名稱的IP地址是多少啊?),根域發現這是一個頂級域com域的一個網域名稱,於是就告訴電訊廠商的DNS我不知道這個網域名稱的IP地址,但是我知道com域的IP地址,你去找它去,於是電訊廠商的DNS就得到了com域的IP地址,又向com域的IP地址發起了請求(請問www.linux178.com這個網域名稱的IP地址是多少?),com域這台伺服器告訴電訊廠商的DNS我不知道www.linux178.com這個網域名稱的IP地址,但是我知道linux178.com這個域的DNS地址,你去找它去,於是電訊廠商的DNS又向linux178.com這個網域名稱的DNS地址(這個一般就是由網域名稱註冊商提供的,像萬網,新網等)發起請求(請問www.linux178.com這個網域名稱的IP地址是多少?),這個時候linux178.com域的DNS伺服器一查,誒,果真在我這裡,於是就把找到的結果發送給電訊廠商的DNS伺服器,這個時候電訊廠商的DNS伺服器就拿到了www.linux178.com這個網域名稱對應的IP地址,並返回給Windows系統核心,核心又把結果返回給瀏覽器,終於瀏覽器拿到了www.linux178.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=pDjwTfa0IAf_FRBNlw1qLDtQ27YBujWp9jPN4q0QSJdNtGtDBK3ja3jyyN2CgxR5aTAywG4SI6V1NypkSyLISWjiFuFQDinhpVn4QE-uLGG&wd=&eqid=9c02bd21001c69170000000556ece297,即使搜尋結果並沒有變,但這個字串是動態改變的,暫時還不知道這裡起到怎樣的作用?(個人感覺:字串中包含了待訪問的網址,點擊之後會產生302重新導向,將頁面轉到目標頁面(待修改,求大神們給我指正))

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

 

十二、重複資料刪除指令碼

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

重複的指令碼會造成不必要的HTTP請求(如果沒有緩衝該指令碼的話),並且執行多餘的JavaScript浪費時間,還有可能造成錯誤。

如何避免重複指令碼呢?

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

2. 實現指令碼管理器模組。

例如:

 1  function insertScript($file) { 2      if(hadInserted($file)) { 3           return; 4       } 5       exeInsert($file); 6    7       if(hasDependencies($file)) { 8    9           $deps = getDependencies($file);10  11          foreach ($deps as $script) {12              insertScript($script);13          }14  15          echo "<script type=‘text/javascript‘ src=‘".getVersion($file)."‘></script>";16  17      }18  }

先檢查是否插入過,如果插入過則返回。如果該指令碼依賴其它指令碼,則被依賴的指令碼也會被插入。最後指令碼被傳送到頁面,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方法,這樣可以使用用戶端的緩衝,提高請求速度。

如果是原創文章,轉載請註明出處:http://www.cnblogs.com/MarcoHan/ 

 

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

web前端效能最佳化

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.