前端性能優化

轉載出處:http://www.cnblogs.com/lei2007/p/3262897.html

除了自己總結:1. 減少http請求,2.壓縮並優化js/css/image 3.儘量靜態頁面,從簡原則 4.代碼規範(詳見:個人知識體系思維導圖)

從yahoo 新學到的:

 

網頁內容

減少http請求次數

80%的響應時間花在下載網頁內容(images, stylesheets, javascripts, scripts, flash等)。減少請求次數是縮短響應時間的關鍵!可以通過簡化頁面設計來減少請求次數,但頁面內容較多可以採用以下技巧。

1. 捆綁文件: 現在有很多現成的庫可以幫你將多個腳本文件捆綁成一個文件,將多個樣式表文件捆綁成一個文件,以此來減少文件的下載次數。例如在asp.net中可以使用ScriptManager,asp.net MVC中的Bundling

2. CSS Sprites: 就是把多個圖片拼成一副圖片,然後通過CSS來控制在什麼地方具體顯示這整張圖片的什麼位置。給大家看個熟悉的Sprites實例。

豆瓣把他的圖標集中在一起,然後我們看他如何控制只顯示第一個圖標的

複製代碼
複製代碼
.app-icon-read {
    background-position
: 0 0;
}
.app-icon {
    background
: url("/pics/app/app_icons_50_5.jpg") no-repeat scroll 0 0 transparent;

    border-radius: 10px 10px 10px 10px;
    box-shadow: 1px 1px 2px #999999;
    display: inline-block;
    height
: 50px;

    width
: 50px;
}
複製代碼
複製代碼

3. Image Maps: 也是將多幅圖拼在一起,然後通過座標來控制顯示導航。這裏有個經典的例子,選中圖片中的某個人就會將你帶到不同的鏈接。

4. Inline images: 通過編碼的字符串將圖片內嵌到網頁文本中。例如下面的inline image的顯示效果爲一個勾選的checkbox。

複製代碼
複製代碼
.sample-inline-png {
    padding-left: 20px;
    background: white url('data:image/png;base64,iVBORw0KGgoAA
AANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD///+l2Z/dAAAAM0l
EQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4Ug9C9zwz3gVLMDA/A6
P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC') no-repeat scroll left top;
}
複製代碼
複製代碼

圖片顯示效果如左圖

減少DNS查詢次數

DNS查詢也消耗響應時間,如果我們的網頁內容來自各個不同的domain (比如嵌入了開放廣告,引用了外部圖片或腳本),那麼客戶端首次解析這些domain也需要消耗一定的時間。DNS查詢結果緩存在本地系統和瀏覽器中一段時間,所以DNS查詢一般是對首次訪問響應速度有所影響。下面是我清空本地dns後訪問博客園主頁dns的查詢請求。看少去還不少哦。

2

避免頁面跳轉

當客戶端收到服務器的跳轉回復時,客戶端再次根據服務器回覆中的location指定的地址再次發送請求,例如以下跳轉回復。

      HTTP/1.1 301 Moved Permanently
      Location: http://example.com/newuri
      Content-Type: text/html
當客戶端遇到這種回覆的時候,用戶只能等待客戶端再次發送請求,有的網站甚至會一直跳n次,跳到他想帶你去的地方…當然在這個時候用戶看不到任何頁面內容,只有瀏覽器的進度條一直在刷新。

緩存Ajax

Ajax可以幫助我們異步的下載網頁內容,但是有些網頁內容即使是異步的,用戶還是在等待它的返回結果,例如ajax的返回是用戶聯繫人的下拉列表。所以我們還是要注意儘量應用以下規則提高ajax的響應速度。

  • 添加Expires 或 Cache-Control報文頭使回覆可以被客戶端緩存
  • 壓縮回復內容
  • 減少dns查詢
  • 精簡javascript
  • 避免跳轉
  • 配置Etags

延遲加載

這裏討論延遲加載需要我們知道我們的網頁最初加載需要的最小內容集是什麼。剩下的內容就可以推到延遲加載的集合中。

Javascript是典型的可以延遲加載內容。一個比較激進的做法是開發網頁時先確保網頁在沒有Javascript的時候也可以基本工作,然後通過延遲加載腳本來完成一些高級的功能。

提前加載

與延遲加載目的相反,提前加載的是爲了提前加載接下來網頁中訪問的資源,下面是提前加載的類型

無條件提前加載:當前網頁加載完成後,馬上去下載一些其他的內容。例如google會在頁面加載成功之後馬上去下載一個所有結果中會用到的image sprite。

3

有條件加載:根據用戶的輸入推斷需要加載的內容,雅虎的示例是search.yahoo.com

4

有預期的的加載:這種情況一般發生在網頁重新設計時,由於用戶經常訪問舊網頁,本地對舊的網頁內容緩存充分從而顯得舊網頁速度很快,而新的網頁內容卻沒有緩存,設計者可以在舊網頁的內容中預先加載一些新網頁中可能用到的內容,這樣新的網頁就會生下來一些需要下載的資源。

減少DOM元素數量

網頁中元素過多對網頁的加載和腳本的執行都是沉重的負擔,500個元素和5000個元素在加載速度上會有很大差別。

想知道你的網頁中有多少元素,通過在瀏覽器中的一條簡單命令就可以算出,

document.getElementsByTagName('*').length

多少算是多了呢?雅虎在寫這篇文章的時候號稱主頁只有700多元素,但現在接近多了一倍。我們的網頁至少別比雅虎還多吧。。。

5

根據域名劃分內容

瀏覽器一般對同一個域的下載連接數有所限制,按照域名劃分下載內容可以瀏覽器增大並行下載連接,但是注意控制域名使用在2-4個之間,不然dns查詢也是個問題。

一般網站規劃會將靜態資源放在類似於static.example.com,動態內容放在www.example.com上。這樣做還有一個好處是可以在靜態的域名上避免使用cookie。後面我們會在cookie的規則中提到。   

減少iframe數量

使用iframe要注意理解iframe的優缺點

優點

  • 可以用來加載速度較慢的內容,例如廣告。
  • 安全沙箱保護。瀏覽器會對iframe中的內容進行安全控制。
  • 腳本可以並行下載

缺點

  • 即使iframe內容爲空也消耗加載時間
  • 會阻止頁面加載
  • 沒有語義

避免404

404我們都不陌生,代表服務器沒有找到資源,我們要特別要注意404的情況不要在我們提供的網頁資源上,客戶端發送一個請求但是服務器卻返回一個無用的結果,時間浪費掉了。

更糟糕的是我們網頁中需要加載一個外部腳本,結果返回一個404,不僅阻塞了其他腳本下載,下載回來的內容(404)客戶端還會將其當成Javascript去解析。

服務器

使用CDN

再次強調第一條黃金定律,減少網頁內容的下載時間。提高下載速度還可以通過CDN(內容分發網絡)來提升。CDN通過部署在不同地區的服務器來提高客戶的下載速度。如果你的網站上有大量的靜態內容,世界各地的用戶都在訪問,我說的是youtube麼?那CDN是必不可少的。事實上大多數互聯網中的巨頭們都有自己的CDN。我們自己的網站可以先通過免費的CDN供應商來分發網頁資源。

添加Expires 或Cache-Control報文頭

這條規則分爲兩個方面,

Gzip壓縮傳輸文件

Gzip通常可以減少70%網頁內容的大小,包括腳本、樣式表、圖片等文件。Gzip比deflate更高效,主流服務器都有相應的壓縮支持模塊。

IIS中內建了靜態壓縮和動態壓縮模塊,如何配製可以參考Enable HTTP Compression of Static Content (IIS 7)Enable HTTP Compression of Dynamic Content (IIS 7)

值得注意的是pdf文件可以從需要被壓縮的類型中剔除,因爲pdf文件本身已經壓縮,gzip對其效果不大,而且會浪費CPU。

配置ETags

雖然標題叫配製ETags,但是這裏你要根據具體情況進行一些判斷。首先Etag簡單來說是通過一個文件版本標識使得服務器可以輕鬆判斷該請求的內容是否有所更新,如果沒有就回復304 (not modified),從而避免下載整個文件。

但是Etags的版本信息即使主流服務器未能很好地支持跨服務器的判斷,比如你從一個服務器集羣中一臺得到Etags,然後發送到了另一臺那麼校驗很有可能會失敗。

如果你遇到這樣的問題,IIS 7中可以通過如下方法將Etag去掉,使用URL Rewrite,然後在web.config中添加如下配製

複製代碼
複製代碼
<rewrite>
   <outboundRules>
      <rule name="Remove ETag">
         <match serverVariable="RESPONSE_ETag" pattern=".+" />
         <action type="Rewrite" value="" />
      </rule>
   </outboundRules>
</rewrite>
複製代碼
複製代碼

IIS8裏提供了一個簡單配製來直接關閉Etag,

複製代碼
複製代碼
<element name="clientCache">
   <attribute name="cacheControlMode" type="enum" defaultValue="NoControl">
          <enum name="NoControl" value="0" />
          <enum name="DisableCache" value="1" />
          <enum name="UseMaxAge" value="2" />
          <enum name="UseExpires" value="3" />
  </attribute>
  <attribute name="cacheControlMaxAge" type="timeSpan" defaultValue="1.00:00:00" />
  <attribute name="httpExpires" type="string" />
  <attribute name="cacheControlCustom" type="string" />
  
<attribute name="setEtag" type="bool" defaultValue="false" />
</element>
複製代碼
複製代碼

儘早flush輸出

網頁後臺程序中我們知道有個方法叫Response.Flush(),一般我們調用它都是在程序末尾,但注意這個方法可以被調用多次。目的是可以將現有的緩存中的回覆內容先發給客戶端,讓客戶端“有活幹”。

那在什麼時候調用這個方法比較好呢?一般情況下我們可以在對於需要加載比較多外部腳本或者樣式表時可以提前調用一次,客戶端收到了關於腳本或其他外部資源的鏈接可以並行的先發請求去下載,服務器接下來把後續的處理結果發給客戶端。

使用GET Ajax請求

瀏覽器在實現XMLHttpRequest POST的時候分成兩步,先發header,然後發送數據。而GET卻可以用一個TCP報文完成請求。另外GET從語義上來講是去服務器取數據,而POST則是向服務器發送數據,所以我們使用Ajax請求數據的時候儘量通過GET來完成。

關於GET和POST的詳細對比可以查看這裏

避免空的圖片src

空的圖片src仍然會使瀏覽器發送請求到服務器,這樣完全是浪費時間,而且浪費服務器的資源。尤其是你的網站每天被很多人訪問的時候,這種空請求造成的傷害不容忽略。

瀏覽器如此實現也是根據RFC 3986 - Uniform Resource Identifiers標準,空的src被定義爲當前頁面。

所以注意我們的網頁中是否存在這樣的代碼

straight HTML 
<img src="">

JavaScript 
var img = new Image(); 
img.src = "";

Cookie

Cookie被用來做認證或個性化設置,其信息被包含在http報文頭中,對於cookie我們要注意以下幾點,來提高請求的響應速度,

  • 去除沒有必要的cookie,如果網頁不需要cookie就完全禁掉
  • 將cookie的大小減到最小
  • 注意cookie設置的domain級別,沒有必要情況下不要影響到sub-domain
  • 設置合適的過期時間,比較長的過期時間可以提高響應速度。

關於asp.net中的cookie可以參考ASP.NET Cookies OverviewConfigure Use Cookies Mode for Session State (IIS 7)

大多數網站的靜態資源都沒必要cookie,我們可以採用不同的domain來單獨存放這些靜態文件,這樣做不僅可以減少cookie大小從而提高響應速度,還有一個好處是有些proxy拒絕緩存帶有cookie的內容,如果能將這些靜態資源cookie去除,那就可以得到這些proxy的緩存支持。

常見的劃分domain的方式是將靜態文件放在static.example.com,動態內容放在www.example.com

也有一些網站需要在二級域名上應用cookie,所有的子域都會繼承,這種情況下一般會再購買一個專門的域名來存放cookie-free的靜態資源。例如Yahoo!的yimg.com,YouTube的ytimg.com等。

CSS

將樣式表置頂

經樣式表(css)放在網頁的HEAD中會讓網頁顯得加載速度更快,因爲這樣做可以使瀏覽器逐步加載已將下載的網頁內容。這對內容比較多的網頁尤其重要,用戶不用一直等待在一個白屏上,而是可以先看已經下載的內容。

如果將樣式表放在底部,瀏覽器會拒絕渲染已經下載的網頁,因爲大多數瀏覽器在實現時都努力避免重繪,樣式表中的內容是繪製網頁的關鍵信息,沒有下載下來之前只好對不起觀衆了。

避免CSS表達式

CSS表達式可以動態的設置CSS屬性,在IE5-IE8中支持,其他瀏覽器中表達式會被忽略。例如下面表達式在不同時間設置不同的背景顏色。

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

CSS表達式的問題在於它被重新計算的次數遠比我們想象的要多,不僅在網頁繪製或大小改變時計算,即使我們滾動屏幕或者移動鼠標的時候也在計算,因此我們還是儘量避免使用它來防止使用不當而造成的性能損耗。

如果想達到類似的效果我們可以通過簡單的腳本做到。

複製代碼
複製代碼
<html>
<head>
</head>
<body>
<script type="text/javascript">
var currentTime = new Date().getHours();
if (currentTime%2) {
    if (document.body) {
        document.body.style.background = "#B8D4FF";
    }
}
else {
    if (document.body) {
        document.body.style.background = "#F08A00";
    }
}
</script>
</body>
</html>
複製代碼
複製代碼

避免使用@import的原因很簡單,因爲它相當於將css放在網頁內容底部。

避免使用Filters

AlphaImageLoad也是IE5.5 - IE8中支持,這種濾鏡的使用會導致圖片在下載的時候阻塞網頁繪製,另外使用這種濾鏡會導致內存使用量的問題。IE9中已經不再支持。

Javascript

將腳本置底

HTTP/1.1 specification建議瀏覽器對同一個hostname不要超過兩個並行下載連接, 所以當你從多個domain下載圖片的時候可以提高並行下載連接數量。但是當腳本在下載的時候,即使是來自不同的hostname瀏覽器也不會下載其他資源,因爲瀏覽器要在腳本下載之後依次解析和執行。

因此對於腳本提速,我們可以考慮以下方式,

  • 把腳本置底,這樣可以讓網頁渲染所需要的內容儘快加載顯示給用戶。
  • 現在主流瀏覽器都支持defer關鍵字,可以指定腳本在文檔加載後執行。
  • HTML5中新加了async關鍵字,可以讓腳本異步執行。

使用外部Javascirpt和CSS文件

使用外部Javascript和CSS文件可以使這些文件被瀏覽器緩存,從而在不同的請求內容之間重用。

同時將Javascript和CSS從inline變爲external也減小了網頁內容的大小。

使用外部Javascript和CSS文件的決定因素在於這些外部文件的重用率,如果用戶在瀏覽我們的頁面時會訪問多次相同頁面或者可以重用腳本的不同頁面,那麼外部文件形式可以爲你帶來很大的好處。但對於用戶通常只會訪問一次的頁面,例如microsoft.com首頁,那inline的javascript和css相對來說可以提供更高的效率。

精簡Javascript和CSS

精簡就是將Javascript或CSS中的空格和註釋全去掉,

複製代碼
複製代碼
body {
    line-height: 1;
}
ol, ul {
    list-style: none;
}
blockquote, q {
    quotes: none;
}
複製代碼
複製代碼

精簡後版本

複製代碼
body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}
複製代碼

統計表明精簡後的文件大小平均減少了21%,即使在應用Gzip的文件也會減少5%。

例如我的網站上有5個CSS,4個Javascirpt,下面是分別經過bundling和minify之後的結果。

沒有任何處理之前 捆綁Javascript和CSS之後 精簡Javascript和CSS之後
6 7 8

用來幫助我們做精簡的工具很多,主要可以參考如下,

JS compressors:

CSS compressors:

與VS集成比較好的工具如下.

去除重複腳本

重複的腳本不僅浪費瀏覽器的下載時間,而且浪費解析和執行時間。一般用來避免引入重複腳本的做法是使用統一的腳本管理模塊,這樣不僅可以避免重複腳本引入,還可以兼顧腳本依賴管理和版本管理。

減少DOM訪問

通過Javascript訪問DOM元素沒有我們想象中快,元素多的網頁尤其慢,對於Javascript對DOM的訪問我們要注意

  • 緩存已經訪問過的元素
  • Offline更新節點然後再加回DOM Tree
  • 避免通過Javascript修復layout

使用智能事件處理

這裏說智能的事件處理需要開發者對事件處理有更深入的瞭解,通過不同的方式儘量少去觸發事件,如果必要就儘早的去處理事件。

比如一個div中10個按鈕都需要事件句柄,那麼我們可以將事件放在div上,在事件冒泡過程中捕獲該事件然後判斷事件來源。

圖片

優化圖像

當美工完成了網站的圖片設計後,我們可以在上傳圖片之前對其做以下優化

  • 檢查GIF圖片中圖像顏色的數量是否和調色板規格一致。如果你發現圖片中只用到了4種顏色,而在調色板的中顯示的256色的顏色槽,那麼這張圖片就還有壓縮的空間。可以使用imagemagick檢查: 
    identify -verbose image.gif
  • 嘗試把GIF格式轉換成PNG格式,看看是否節省空間。大多數情況下是可以壓縮的。下面這條簡單的命令可以安全地把GIF格式轉換爲PNG格式: 
    convert image.gif image.png
  • 在所有的PNG圖片上運行pngcrush(或者其它PNG優化工具)。例如: 
    pngcrush image.png -rem alla -reduce -brute result.png
  • 在所有的JPEG圖片上運行jpegtran。這個工具可以對圖片中的出現的鋸齒等做無損操作,同時它還可以用於優化和清除圖片中的註釋以及其它無用信息 
    jpegtran -copy none -optimize -perfect src.jpg dest.jpg

優化CSS Sprite

  • Spirite中水平排列圖片,垂直排列會增加文件大小;
  • Spirite中把顏色較近的組合在一起可以降低顏色數,理想狀況是低於256色以便適用PNG8格式;
  • 不要在Spirite的圖像中間留有較大空隙。這雖然不大會增加文件大小,但對於用戶代理來說它需要更少的內存來把圖片解壓爲像素地圖。100×100的圖片爲1萬像素,1000×1000就是100萬像素。

不要在HTML中縮放圖片

不要通過圖片縮放來適應頁面,如果你需要小圖片,就直接使用小圖片吧。

使用小且可緩存的favicon.ico

網站圖標文件favicon.ico,不管你服務器有還是沒有,瀏覽器都會去嘗試請求這個圖標。所以我們要確保這個圖標

  • 存在
  • 文件儘量小,最好小於1k
  • 設置一個長的過期時間

移動客戶端

保持單個內容小於25KB

這限制是因爲iphone,他只能緩存小於25K,注意這是解壓後的大小。所以單純gzip不一定夠用,精簡文件工具要用上了。

打包組建成符合文檔

把頁面內容打包成複合文本就如同帶有多附件的Email,它能夠使你在一個HTTP請求中取得多個組建。當你使用這條規則時,首先要確定用戶代理是否支持(iPhone不支持)。

ths:

http://www.cnblogs.com/developersupport/p/webpage-performance-best-practices.html


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章