[轉] 《高性能HTML5》讀後整理的Web性能優化內容

  • 讀後感

        先說說《高性能HTML5》這本書的讀後感吧,我的以爲這本書前兩章跟書的標題徹底搭不上關係,或者說只能算是講解了「高性能」這三個字,HTML5徹底不見蹤跡。我的以爲做者應該首先把HTML5的大菜拿出來說一講,再去分析性能優化的內容,這樣纔會有吸引力。由於只是在線試讀,沒有機會看後面的內容,因此不胡亂評價了。javascript

 

        雖然我以爲這本書沒說到點子上,但仍是從「高性能」方面學到了不少東西------又一次擴大了知識面!之前,我一直認爲一套架構穩定、後臺高質量的代碼就能讓系統高效,但讀完這本書兩章內容以後,發現前端有那麼多能夠提升性能的方式,一直被我輕視的前臺技術也能有這麼「花哨」,又一次井底之蛙了- -||。css

 

        在看完這兩章內容以後,我意猶未盡,因而乎從網上搜索關鍵字「Java Web高性能」,在IBM社區找到兩篇不錯的文章,而讓人更意外的是我發現那兩篇文章的內容跟《高性能HTML5》前兩章高度類似,不知道是誰抄襲誰的,你們能夠鑑別下真僞,下面附上地址。html

        http://dl2.iteye.com/upload/attachment/0097/9373/b0e69540-e703-3530-81bb-c93de7b850a6.pdf前端

        http://www.ibm.com/developerworks/cn/java/j-lo-javawebhiperf1/java

        http://www.ibm.com/developerworks/cn/java/j-lo-javawebhiperf2/        css3

 

        前面是讀後感,下面是我針對最近幾天學習到的提升Web性能進行了篇幅不小的總結,一來爲新人提供幫助,二來本身作一下筆記,加深記憶。程序員

 

  •  性能以前端篇

--減小重繪web

        在HTML頁面完成展示以後,動態改變頁面元素或調整CSS樣式都會引發瀏覽器重繪,性能的損耗直接取決於動態改變的範圍:若是隻是改變一個元素的顏色之類的信息則只會重繪該元素;而若是是增刪節點或調整節點位置則會引發其兄弟節點也一併重繪。數組

        減小重繪並非說不要重繪,而是要注意重繪範圍:①改動的DOM元素越深則影響越小,因此儘可能深刻節點改動;②對某些DOM樣式有多重變更儘可能合併到一塊兒修改。瀏覽器

 

以改變一個<a>標籤的背景色、寬度和顏色爲例。

 

Html代碼   收藏代碼
  1. <href="javascript:void(0);" id="example">傳統的代碼</a>   
  2. <script>   
  3.  var example = document.getElementById("example");   
  4.  example.ondblclick = function() {   
  5.  example.style.backgroundColor = "red";   
  6.  example.style.width = "200px";   
  7.  example.style.color = "white";   
  8.  }   
  9. </script>   

 以上會執行3次重繪,而經過CSS代替javascript屢次執行則只進行一次重繪。

 

 

Html代碼   收藏代碼
  1. <style>   
  2.  .dblClick {   
  3.  width: 200px;   
  4.  background: red;   
  5.  color: white;   
  6.  }   
  7. </style>   
  8. <href="javascript:;" id="example">CSS優化的代碼</a>   
  9. <script>   
  10.  var example = document.getElementById("example");   
  11.  example.ondblclick = function() {   
  12.  example.className = "dblClick";   
  13.  }   
  14. </script>  

 

 

--避免腳本阻塞加載

        當瀏覽器在解析常規的script標籤時,它須要等待script下載完畢,再解析執行,然後續的HTML代碼只能等待。CSS文件引入要放在<head>頭部,由於這是HTML渲染必備元素。爲了不阻塞加載,應把腳本放到文檔的末尾,而CSS是須要放在頭部的!

 

Html代碼   收藏代碼
  1. <head>  
  2. <link rel="stylesheet" href="common.css">  
  3. ......  
  4. <script src="example.js"></script>  
  5. </body>  

 

 

--避免節點深層級嵌套

        深層級嵌套的節點在初始化構建時每每須要更多的內存佔用,而且在遍歷節點時也會更慢些,這與瀏覽器構建DOM文檔的機制有關。瀏覽器會把整個HTML文檔的結構存儲爲DOM「樹」結構。當文檔節點的嵌套層次越深,構建的DOM樹層次也會越深。

 

以下代碼,徹底可以去掉<div>或<span>其中一個標籤。

 

Html代碼   收藏代碼
  1. <div>  
  2.   <span>  
  3.     <label>嵌套</label>  
  4.   </span>  
  5. </div>  

 

 

--頁面緩存

        一般不設置緩存的狀況下,每次刷新頁面都會從新讀取服務器的文件,而若是設置緩存以後,全部文件均可以從本地取得,這樣明顯極大提升了頁面效率。

 

咱們能夠經過設置頁面頭的expires來定義頁面過時時間,將過時時間定久一點就達到了「永久」緩存。

 

Html代碼   收藏代碼
  1. <meta http-equiv="expires" content="Sunday 26 October 2099 01:00 GMT" />  

 固然,若是你的項目代碼有變動,由於客戶端緩存了文件就得不到最新的文件,勢必形成顯示錯誤。基於這個問題的解決方案就是給連接文件加一個時間戳,若是時間戳有變化,瀏覽器會認爲是新文件,就會向服務器請求最新文件。

 

 

Html代碼   收藏代碼
  1. <script src="example2014-6-17.js"></script>  
  2. //若是是JSP,能夠用EL表達式來取時間戳信息,這樣管理更加方便  
  3. <script src="example${your time param}.js"></script>  
  4. //或者這樣的寫法更優秀:  
  5. <script src="example.js?time=2014-6-7"></script>  
  6. <script src="example.js?time=${your time param}"></script>  

 

 

--壓縮合並文件

        全部涉及到請求數據的文件儘可能作壓縮,好比Javascript文件、css文件及圖片文件,特別是圖片文件,若是沒有高清晰要求,徹底能夠壓縮後再使用。

        數量少體積大的文件要比數量多體積小的文件加載速度快,因此有時候能夠考慮將多個js文件、多個css文件合併在一塊兒。

 

除此以外減小HTML文檔大小還能夠採起下面幾種方法:

①刪掉HTM文檔對執行結果無影響的空格空行和註釋

②避免Table佈局

③使用HTML5

 

--HTML+CSS3+Javascript各司其職

        讓三元素各司其職才能作出高性能的網頁:HTML是頁面之本也是內容之源,有了它就能跟CSS和Javascript交互;CSS3能夠說是展示大師,並且日漸強大的CSS能代替Javascript作不少動態的事情如漸變、移動等動態效果;Javascript是動態數據之王,舊瀏覽器依靠js來完成動態效果展示,但如今的CSS也能完成js的工做,因此儘可能將工做交給css,這樣會得到更好的性能。(這個說得有點大)

 

--圖像合併實現CSS Sprites

        圖像合併其實就是把網頁中一些背景圖片整合到一張圖片文件中,再利用CSS 的「background-image」,「background- repeat」,「background-position」的組合進行背景定位,background-position能夠用數字能精確的定位出背景圖片的位置。

        一個頁面要用到多個圖標,徹底能夠將多個圖標合併成一個圖,而後只須要發一次圖片請求,經過css定位分割圖標便可。

 

--避免使用Iframe

        使用iframe並不會增長同域名下的並行下載數,瀏覽器對同域名的鏈接老是共享瀏覽器級別的鏈接池,在頁面加載過程當中iframe元素還會阻塞父文檔onload事件的觸發。而且iframe是html標籤中最消耗資源的標籤,它的開銷比DIV、SCRIPT、STYLE等DOM高1~2個數量級。

 

避免onload事件被阻塞,可以使用JavaScript動態的加載iframe元素或動態設置iframe的src屬性(但其僅在高級瀏覽器IE9及以上有效)。

 

Html代碼   收藏代碼
  1. <iframe id="if"></iframe>  
  2. document.getElementById("if").setAttribute("src","url");  

 

 

--多域名請求

        通常來講,瀏覽器對於相同域名的圖片,最多用2-4個線程並行下載(不一樣瀏覽器的併發下載數是不一樣的)。而相同域名的其餘圖片,則要等到其餘圖片下載完後纔會開始下載。

        有時候,圖片數據太多,一些公司的解決方法是將圖片數據分到多個域名的服務器上,這在一方面是將服務器的請求壓力分到多個硬件服務器上,另外一方面,是利用了瀏覽器的特性。(你們能夠去新浪、騰訊門戶網站查看,這些大型站點同一頁面加載的圖片可能由多個站點提供)

        注:一個HTML請求的域名也不要太多(2~3個差很少),多了可能形成不一樣服務器鏈接時間差別,反而影響速度。

 

--避免空連接屬性

        如<img src=""><a href="">這樣的設置方式是很是不可取的,即便連接爲空,在舊的瀏覽器也會以固定步驟發送請求信息。

        另外<a href="#"></a>也不可取,最好的方式是在連接中加一個空的js代碼<a href="javascript:void();"></a>

 

--使用圖像的BASE64編碼

        base64是一串字符串,他能夠表明一個圖片的全部信息,也就是能夠經過<img src="data:image/png;base64,S">(S表示一串base64碼)來顯示圖片,這種方式不須要再向服務器發送請求,徹底由瀏覽器解析成圖片。

        目前高級瀏覽器都支持此功能,但要注意兩點:①低版本瀏覽器(如IE7)不支持;②base64字符串長度隨圖片的大小及複雜度成正比,base64也像URL同樣,也有超出長度的狀況(在IE8下很常見)。因此要根據狀況來使用。

 

--顯式設置圖片的寬高

        若是HTML裏的圖片沒有指定尺寸(寬和高),或者代碼描述的尺寸與實際圖片的尺寸不符時,瀏覽器則要在圖片下載完成後再「回溯」該圖片並從新顯示,這會消耗額外時間。

<img src="demo.jpg" width="200" height="200">

 

--顯式指定文檔字符集

        若是瀏覽器不能獲知頁面的編碼字符集,通常都會在執行腳本和渲染頁面前,把字節流緩存,而後再搜索可進行解析的字符集,或以默認的字符集來解析頁面代碼,這會致使消耗沒必要要的時間。

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

 

--漸進式加強設計

        漸進式加強設計的通俗解釋就是:首先寫一段知足全部瀏覽器的基本樣式,再在後面針對不一樣高級瀏覽器編寫更漂亮的樣式

        以下代碼,全部瀏覽器都支持background-color: #2067f5;知足了瀏覽器基本現實需求,然後面的background-image: -webkit-gradient等則爲不一樣高級瀏覽器使用,只要瀏覽器識別就能執行這段代碼(不識別,CSS也不會報錯只會直接忽略)。

 

Html代碼   收藏代碼
  1. <div class="someClass"></div>   
  2. .someClass   
  3. { width: 100px;   
  4.  height: 100px;   
  5.  background-color: #2067f5;   
  6.  background-image: -webkit-gradient(linear, left top, left bottom, from(#2067f5),   
  7. to(#154096));   
  8.  background-image: -webkit-linear-gradient(top, #2067f5, #154096);   
  9.  background-image: -moz-linear-gradient(top, #2067f5, #154096);   
  10.  background-image: -ms-linear-gradient(top, #2067f5, #154096);   
  11.  background-image: -o-linear-gradient(top, #2067f5, #154096);   
  12.  background-image: linear-gradient(to bottom, #2067f5, #154096);   
  13. }  

參考閱讀:多瀏覽器適配測試

 

 

--懶加載與預加載

        預加載和懶加載,是一種改善用戶體驗的策略,它實際上並不能提升程序性能,可是卻能夠明顯改善用戶體驗或減輕服務器壓力。

        預加載表示當前用戶在請求到須要的數據以後,頁面自動預加載下一次用戶可能要看的數據,這樣用戶下一次操做的時候就馬上呈現,依次類推。

        懶加載表示用戶請求什麼再顯示什麼,若是一個請求要響應的時間很是長,就不推薦懶加載。

 

--Flush機制

        當一個頁面很是大,內容很是多,能夠採用flush的形式分部分返回給頁面,這樣能告訴用戶我正在工做,顯示一部份內容比白屏等很長時間要好得多。在Java Web技術中,實現Flush很是簡單,只要調用 HttpServletResponse.getWriter輸出流的flush方法,就能夠將已經完成加載的內容寫回給客戶端。

        這種方式只適用於返回數據特別多、請求時間特別長的狀況,常規數據仍是用正常的實時所有返回最佳。這種實現方式實際會增長瀏覽器渲染時間和用戶總體等待時間,但從用戶體驗上會更加優秀。

 

  • 性能之服務器優化

--CDN機制

        所謂的CDN,就是一種內容分發網絡,它採用智能路由和流量管理技術,及時發現可以給訪問者提供最快響應的加速節點,並將訪問者的請求導向到該加速節點,由該加速節點提供內容服務。

        通俗點說,你在成都(瀏覽器)購買了北京賣家(服務器)的產品,北京賣家經過快遞(CDN服務)寄送包裹,從北京到成均可以走路、坐汽車、火車或飛機,而採用CND的快遞會選擇飛機直達,由於這種寄送方式最快。

 

固然使用CDN有兩個注意事項:

一、CDN加速服務很貴,若是你以爲你的網站值得加速,能夠選擇購買;

二、CDN不適合局域性網站,好比你的網站只有某一個片區訪問或者局域網訪問,由於區域性網絡原本就很近,無需CDN加速。

 

--HTTP協議的合理使用

        瀏覽器緩存帶來的性能提高已經衆人皆知了,而不少人卻並不知道瀏覽器的緩存過時時間、緩存刪除、什麼頁面能夠緩存等,均可以由咱們程序員來控制,只要您熟悉HTTP協議,就能夠輕鬆的控制瀏覽器。

 

擴展閱讀:深刻理解HTTP協議

 

--動靜分離

        所謂的動靜分離,就是將Web應用程序中靜態和動態的內容分別放在不一樣的Web服務器上,有針對性的處理動態和靜態內容,從而達到性能的提高。咱們知道若是一個HTML有多個域名請求數據文件會提升

Tomcat服務器在處理靜態和併發問題上比較弱,因此事先動靜分離的方式通常會用Apache+Tomcat、Nginx+Tomcat等。

        以Apache+Tomcat爲例,其運行機理是:頁面請求首先給Apache,而後Apache分析請求信息是靜態仍是動態,靜態則本機處理,動態則交給Tomcat作處理。

        這實際上是負載均衡的雛形,這樣的實現不用讓開發人員作任何特殊開發,一個<img src="demo.jpg">交給服務器便可,至於這個文件是從Apache仍是從Tomcat取得,開發人員徹底無需關注。

 

--HTTP持久鏈接

        持久鏈接(Keep-Alive)也叫作長鏈接,它是一種TCP的鏈接方式,鏈接會被瀏覽器和服務器所緩存,在下次鏈接同一服務器時,緩存的鏈接被從新使用。HTTP無狀態性表示了它不屬於長鏈接,但HTTP/1.1提供了對長鏈接的支持(不過這必須依賴瀏覽器和服務器雙方均支持長鏈接功能才行),最多見的HTTP長鏈接例子是「斷點下載」。

        瀏覽器在請求的頭部添加 Connection:Keep-Alive,以此告訴服務器「我支持長鏈接,你支持的話就和我創建長鏈接吧」,而假若服務器的確支持長鏈接,那麼就在響應頭部添加「Connection:Keep-Alive」,從而告訴瀏覽器「個人確也支持,那咱們創建長鏈接吧」。服務器還能夠經過Keep-Alive:timeout=..., max=...的頭部告訴瀏覽器長鏈接失效時間。

        配置長鏈接一般是要服務器支持設置,有測試數據顯示,使用長鏈接和不使用長鏈接的性能對比,對於Tomcat配置的maxKeepAliveRequests爲50來講,效率居然提高了將近5倍。

 

--GZIP壓縮技術

        HTTP協議支持GZIP的壓縮格式,當服務器返回的HTML信息報頭中包含Content-Encoding:gzip,它就告訴瀏覽器,這個響應的返回數據已經壓縮成GZIP格式,瀏覽器得到數據後要進行解壓縮操做,必定程度上減輕了服務器傳輸數據的壓力。

        不少服務器已經支持經過配置來自動將HTML信息壓縮成GZIP,好比tomcat、又好比很火的Nginx。若是沒法配置服務器級別的GZIP壓縮機制,能夠改成程序壓縮。

 

Java代碼   收藏代碼
  1.  // 監視對 gzipCategory 文件夾的請求  
  2.  @WebFilter(urlPatterns = { "/gzipCategory/*" })   
  3.  public class GZIPFilter implements Filter {   
  4.   
  5.  @Override   
  6.  public void doFilter(ServletRequest request, ServletResponse response,   
  7.  FilterChain chain) throws IOException, ServletException {   
  8.  String parameter = request.getParameter("gzip");   
  9.  // 判斷是否包含了 Accept-Encoding 請求頭部  
  10.  HttpServletRequest s = (HttpServletRequest)request;   
  11.  String header = s.getHeader("Accept-Encoding");   
  12.  //"1".equals(parameter) 只是爲了控制,若是傳入 gzip=1,才執行壓縮,目的是測試用  
  13.  if ("1".equals(parameter) && header != null && header.toLowerCase().contains("gzip")) {   
  14.  HttpServletResponse resp = (HttpServletResponse) response;   
  15.  final ByteArrayOutputStream buffer = new ByteArrayOutputStream();   
  16.   
  17.  HttpServletResponseWrapper hsrw = new HttpServletResponseWrapper(   
  18.  resp) {   
  19.   
  20.  @Override   
  21.  public PrintWriter getWriter() throws IOException {   
  22.  return new PrintWriter(new OutputStreamWriter(buffer,   
  23.  getCharacterEncoding()));   
  24.  }   
  25.   
  26.  @Override   
  27.  public ServletOutputStream getOutputStream() throws IOException {   
  28.  return new ServletOutputStream() {   
  29.   
  30.  @Override   
  31.  public void write(int b) throws IOException {   
  32.  buffer.write(b);   
  33.  }   
  34.  };   
  35.  }   
  36.   
  37.  };   
  38.   
  39.  chain.doFilter(request, hsrw);   
  40.  byte[] gzipData = gzip(buffer.toByteArray());   
  41.  resp.addHeader("Content-Encoding", "gzip");   
  42.  resp.setContentLength(gzipData.length);   
  43.  ServletOutputStream output = response.getOutputStream();   
  44.  output.write(gzipData);   
  45.  output.flush();   
  46.  } else {   
  47.  chain.doFilter(request, response);   
  48.  }   
  49.  }   
  50.  // 用 GZIP 壓縮字節數組  
  51.  private byte[] gzip(byte[] data) {   
  52.  ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(10240);   
  53.  GZIPOutputStream output = null;   
  54.  try {   
  55.  output = new GZIPOutputStream(byteOutput);   
  56.  output.write(data);   
  57.  } catch (IOException e) {   
  58.  } finally {   
  59.  try {   
  60.  output.close();   
  61.  } catch (IOException e) {   
  62.  }   
  63.  }   
  64.  return byteOutput.toByteArray();   
  65.  }   
  66. ……  
  67.  }  

 

 

  • 總結

        細節決定成敗,系統慢是由一個又一個不良的小細節形成的,因此開發初期作好充足的準備,開發中認真負責、不偷工減料,維護期更要注重代碼質量,這樣才能讓咱們的系統穩定高效。

        我的以爲一個產品的新版本質量能夠從核心js文件看出來:若是核心js文件大小比上一版本大太多,明顯在性能上就會有問題,咱們要爭作像谷歌、亞馬遜這樣優秀的團隊--可以在功能升級的同時減少核心js文件大小。

相關文章
相關標籤/搜索