毫秒必爭,前端網頁性能最佳實踐

你願意爲打開一個網頁等待多長時間?我一秒也不肯意等。可是事實上大多數網站在響應速度方面都讓人失望。如今愈來愈多的人開始創建本身的網站,博客,你的網頁響應速度如何呢?在這篇文章中咱們來介紹一下提升網頁性能的最佳實踐,以及相應的問題解決方案,讓站長或者即將要成爲站長的朋友瞭解如何去測試和提升網站響應速度,對本身的網站更有信心。javascript


最佳實踐css


最佳實踐咱們引用的來自yahoo前端性能團隊總結的35條黃金定律。原文猛擊這裏。下面咱們分門別類將每條的關鍵點總結一下。html


網頁內容前端


  • 減小http請求次數java

  • 減小DNS查詢次數web

  • 避免頁面跳轉ajax

  • 緩存Ajaxexpress

  • 延遲加載瀏覽器

  • 提早加載緩存

  • 減小DOM元素數量

  • 根據域名劃份內容

  • 減小iframe數量

  • 避免404


服務器


  • 使用CDN

  • 添加Expires 或Cache-Control報文頭

  • Gzip壓縮傳輸文件

  • 配置ETags

  • 儘早flush輸出

  • 使用GET Ajax請求

  • 避免空的圖片src


Cookie


  • 減小Cookie大小

  • 頁面內容使用無cookie域名


CSS


  • 將樣式表置頂

  • 避免CSS表達式

  • 用<link>代替@import

  • 避免使用Filters


Javascript


  • 將腳本置底

  • 使用外部Javascirpt和CSS文件

  • 精簡Javascript和CSS

  • 去除重複腳本

  • 減小DOM訪問

  • 使用智能事件處理


圖片


  • 優化圖像優化CSS Sprite不要在HTML中縮放圖片使用小且可緩存的favicon.ico


移動客戶端


  • 保持單個內容小於25KB

  • 打包組建成符合文檔


網頁內容


減小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的查詢請求。看少去還很多哦。



避免頁面跳轉


當客戶端收到服務器的跳轉回復時,客戶端再次根據服務器回覆中的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。



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



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


減小DOM元素數量


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


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


document.getElementsByTagName('*').length


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



根據域名劃份內容


瀏覽器通常對同一個域的下載鏈接數有所限制,按照域名劃分下載內容能夠瀏覽器增大並行下載鏈接,可是注意控制域名使用在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報文頭


這條規則分爲兩個方面,


  • 對於靜態內容添加Expires,將靜態內容設爲永不過時,或者很長時間之後。在IIS中設置Expires能夠看Configure the HTTP Expires Response Header (IIS 7)。

  • 對於動態內容應用合適的Cache-Control,讓瀏覽器根據條件來發送請求。關於asp.net的caching,能夠看asp.net cache feature和asp.net caching best practices。


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大小


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


  • 去除沒有必要的cookie,若是網頁不須要cookie就徹底禁掉

  • 將cookie的大小減到最小

  • 注意cookie設置的domain級別,沒有必要狀況下不要影響到sub-domain

  • 設置合適的過時時間,比較長的過時時間能夠提升響應速度。


關於asp.net中的cookie能夠參考ASP.NET Cookies Overview和Configure Use Cookies Mode for Session State (IIS 7)


頁面內容使用無cookie域名


大多數網站的靜態資源都不必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>


用<link>代替@import


避免使用@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以後



用來幫助咱們作精簡的工具不少,主要能夠參考以下,


JS compressors:


  • Packer

  • JSMin

  • Closure compiler

  • YUICompressor(also does CSS)

  • AjaxMin(also does CSS)


CSS compressors:


  • CSSTidy

  • Minify

  • YUICompressor(also does JS)

  • AjaxMin(also does JS)

  • CSSCompressor


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


  • YUICompressor- 編譯集成,包含在NuGet.

  • AjaxMin – 編譯集成


去除重複腳本


重複的腳本不只浪費瀏覽器的下載時間,並且浪費解析和執行時間。通常用來避免引入重複腳本的作法是使用統一的腳本管理模塊,這樣不只能夠避免重複腳本引入,還能夠兼顧腳本依賴管理和版本管理。


減小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不支持)。

相關文章
相關標籤/搜索