web前端性能優化

引言

前端是龐大的,包括HTMLCSSJavascriptImageFlash等等各類各樣的資源。javascript

前端優化是複雜的,針對方方面面的資源都有不一樣的方式。那麼,前端優化的目的是什麼 ?css

  • 用戶角度而言,優化可以讓頁面加載得更快、對用戶的操做響應得更及時,可以給用戶提供更爲友好的體驗。
  • 服務商角度而言,優化可以減小頁面請求數、或者減少請求所佔帶寬,可以節省可觀的資源。

資源的合併與壓縮

1. 資源的合併(減小http請求數量)

如上圖所示,文件不合並存在的問題:html

  1. 文件與文件之間有插入的上行請求,增長了N-1個網絡延遲。
  2. 丟包問題影響更嚴重,每次網絡請求都會存在丟包的狀況。
  3. keep-alive通過代理服務器時可能會被斷開 ,不必定能完成狀態的保持。

可是進行文件合併也是存在的問題:前端

  1. 首屏渲染問題: 在進行js文件合併後,文件明顯變大、請求時間變長。當html網頁進行渲染時,若該渲染須要依賴這個js的話,那頁面渲染會等到js文件請求以後回來纔會繼續進行,致使首屏渲染時間延遲。
  2. 緩存失效問題:若如今有a、b、c三個文件合併,只要任意改變其中一個文件都會致使這個合併文件緩存失效,因此文件合併容易致使大面積緩存失效。

對於文件合併有如下三個建議vue

  1. 公共庫合併 ,業務代碼單獨處理。
  2. 不一樣頁面的js文件單獨打包。
  3. 在真實場景作相應處理,怎麼合適怎麼來 。

如何進行文件合併:java

  1. 使用在線網站進行文件合併 。
  2. 在構建階段,使用nodejs實現文件合併。(webpackgulpfis3等)

2. 資源的壓縮(減小請求資源的大小)

  1. HTML壓縮 HTML代碼壓縮就是壓縮一些在文本文件中有意義,可是在HTML中不顯示的字符,包括空格製表符換行符等,還有一些其餘意義的字符,如HTML註釋也能夠被壓縮。 node

  2. CSS壓縮 CSS代碼壓縮就是對一些無效代碼刪除CSS語義合併。對於咱們來講無效代碼多是註釋,也多是無效字符。 android

  3. JS壓縮與混亂 JS代碼壓縮就是對一些無效字符的刪除剔除註釋代碼語義的縮減和優化(如變量名縮短等)和代碼保護。(代碼進行壓縮與混亂防止代碼邏輯被輕易窺探)webpack

  4. 如何進行HTML、CSS、JS壓縮ios

  5. 使用在線網站進行壓縮。

  6. 結合nodejs使用webpackgulpfis3等工具。

圖片的優化

1. 各類類型的圖片

不一樣格式圖片經常使用的業務場景

  • jpg有損壓縮,壓縮率高,不支持透明 —— 大部分不須要透明圖片的業務場景
  • png支持透明,瀏覽器兼容好 (可降階壓縮:png3二、png2四、png8) —— 大部分須要透明圖片的業務場景
  • webp壓縮程度更好,在ios webview有兼容性問題 ,在android中支持比較好 —— 安卓開發
  • svg矢量圖,代碼內嵌,相對較小 —— 圖片樣式相對簡單的業務場景(小的icon、logo等)
  • gif支持透明、體積小、成像相對清晰(靜態GIF和動畫GIF) —— 與其餘4種圖片的使用場景基本不衝突

壓縮後的大小:png > jpg > webp

一個好用的圖片優化平臺

2. 進行圖片壓縮

  1. Css雪碧圖:把一些圖片整合到一張單獨的圖片中
  • 優勢:減小你的網站的HTTP請求數量。
  • 缺點:整合圖片比較大時,一次加載比較慢,替換圖片也比較麻煩。
  1. Image inline:將圖片的內容內嵌到html當中
  • 優勢:減小你的網站的HTTP請求數量。
  • 缺點:適合比較小的圖。
  1. 使用SVG矢量圖

CSS和JS的裝載與執行

1. HTML渲染過程的特色

  1. 順序執行
  • 進行詞法分析,從上到下。
  1. 併發加載
  • 外部資源併發請求,併發度受瀏覽器域名限制,單個域名併發度是有限制的。
  1. 是否阻塞
  • css在head中經過link方式引入的話會阻塞頁面的渲染。
  • css不阻塞外部資源的加載 ,會阻塞js的執行。
  • js的引入會阻塞html文檔的分析、頁面的渲染。
  • js不阻塞外部資源的加載。
  • js順序執行,阻塞後續js邏輯的執行。
  1. 依賴關係
  • 頁面渲染依賴於css的加載。
  • js的執行順序是有依賴關係。
  • js邏輯對於dom節點的依賴關係。
  1. 引入方式(js)
  • 腳本直接引入:瀏覽器會當即加載並執行腳本,js的加載和執行會阻塞頁面的渲染。(同步)
  • defer方式引入:不會阻塞頁面的渲染,執行時間延遲到dom樹構建完成後(DOMContentLoaded事件觸發以前完成,保證能拿到dom元素),順序執行。(異步)
  • async方式引入:不會阻塞頁面的渲染,onload事件觸發前執行,不保證執行順序,腳本一旦加載完畢就會馬上執行。(異步)
  • 動態建立script方式:代碼動態建立script方式引入,將script標籤插入到DOM中。(異步)

DOMContentloaded與onload的區別

  • 當onload事件觸發時,頁面上全部的DOM、樣式表、腳本、圖片、flash都已經加載完成。
  • 當DOMContentloaded事件觸發時,僅當DOM加載完成,不包括樣式表、腳本、圖片、flash。

2. 加載和執行的一些優化點

  1. css 樣式表置頂
  • 會阻塞頁面的渲染,防止頁面在沒有css樣式的狀況下渲染出來。
  1. 用link代替import引入css
  • import不會觸發瀏覽器併發機制,頁面加載渲染完成以後纔會進行import的工做(目前有的高版本的瀏覽器,link和import的做用沒有區別),可是引用層數仍是有影響併發。
  1. js 腳本置底
  • 不阻塞頁面的渲染和css的加載,使css資源儘可能在第一批併發下載中,讓頁面更快的呈現給用戶。
  1. 合理使用js的異步加載

懶加載和預加載

1. 懶加載

  1. 原理
  • 當圖片進入可視區域後請求圖片資源,須要去監聽scroll事件的回調,去判斷咱們的懶加載圖片是否進入可視區域。
  • 注意getBoundingClientRect用於獲取某個元素相對於視窗的位置集合,若圖片top小於視窗的高度,說明進入可視區域。
  1. 優勢
  • 減小無效資源的加載。
  • 併發加載資源過多會阻塞js的加載,影響網站的正常使用。
  1. 實現方式
  • 本身編寫懶加載代碼lazyload.js
<!doctype html>
<html>
  <head>
    <title>懶加載</title>
  </head>
  <body>
    <div class="image-list">
      <img src="" class="image-item" lazyload="true" data-original="http://xxx.xxx.1.jpg" />
      <img src="" class="image-item" lazyload="true" data-original="http://xxx.xxx.2.jpg" />
      <img src="" class="image-item" lazyload="true" data-original="http://xxx.xxx.3.jpg" />
      <img src="" class="image-item" lazyload="true" data-original="http://xxx.xxx.4.jpg" />
      <img src="" class="image-item" lazyload="true" data-original="http://xxx.xxx.5.jpg" />
      <img src="" class="image-item" lazyload="true" data-original="http://xxx.xxx.6.jpg" />
      <img src="" class="image-item" lazyload="true" data-original="http://xxx.xxx.7.jpg" />
      <img src="" class="image-item" lazyload="true" data-original="http://xxx.xxx.8.jpg" />
      <img src="" class="image-item" lazyload="true" data-original="http://xxx.xxx.9.jpg" />
      <img src="" class="image-item" lazyload="true" data-original="http://xxx.xxx.10.jpg" />
    </div>
    <script>
      var viewHeight = document.documentElement.clientHeight; //獲取可視區域的高度
      function lazyload () {
        var eles = document.querySelectorAll('img[data-original][lazyload]'); //獲取須要懶加載的元素
        Array.prototype.forEach.call(eles, function (item, index) {
          var rect;
          if (item.dataset.original === '') return;

          rect = item.getBoundingClientRect(); //獲取元素的大小及其相對於視口的位置集合,集合中有top, right, bottom, left等屬性。
          if (rect.bottom >= 0 && rect.top < viewHeight) { //判斷元素是否進入可視區域
            !function () { //當即執行匿名函數,加載圖片
              var img = new Image();
              img.src = item.dataset.original;
              img.onload = function () {
                item.src = img.src;
              }
              item.removeAttribute('data-original');
              item.removeAttribute('lazyload');
            }()
          }
        })
      }

      lazyload(); //初始化懶加載方法
      document.addEventListener('scroll', lazyload); //添加頁面滾動監聽器
    </script>  
  </body>
</html>
複製代碼
  • 使用網上分享的lazyload庫。

2. 預加載

  1. 原理
  • 圖片等靜態資源在使用前提早請求。
  1. 優勢
  • 資源使用時能從緩存中加載,提高用戶體驗。
  1. 實現方式
  • <img src="http://..." style="display: none" />
  • 使用Image對象,var image = new Image();image.src = "http://...";
  • 使用XMLHttpRequest對象,更好去控制預加載的過程,存在跨域問題。
  • 使用PreloadJS,提供了一個一致的方式預先加載在HTML應用的內容,以及預加載可使用HTML標籤做爲XHR完成。

迴流與重繪

1. css性能讓javascript變慢

  • 頻繁觸發重繪與迴流,會致使UI頻繁渲染,最終致使js變慢。

2. 迴流

  • 當render tree中的一部分(或所有)由於元素的規模尺寸,佈局,隱藏等改變而須要從新構建,這就稱爲迴流(reflow)。當頁面佈局和幾何屬性改變時就須要迴流。

3. 重繪

  • 當render tree中的一些元素須要更新屬性,而這些屬性只是影響元素的外觀,風格,而不會影響佈局的,好比background-color。則就稱爲重繪(repaint)。

4. 迴流與重繪關係

  • 迴流必將引發重繪,而重繪不必定會引發迴流。

5. 觸發頁面重佈局(迴流)的屬性

6. 只觸發重繪的屬性

7. 新建DOM的過程

一、獲取DOM後分隔爲多個圖層
二、對每一個圖層的節點計算樣式結果(recalculate style)
三、爲每一個節點生成圖形和位置(layout、reflow和重佈局)
四、將每一個節點繪製填充到圖層位圖彙總(paint,repaint)
五、圖層做爲紋理加載到GPU
六、合併多個圖層到頁面上,生成最終圖像(composite layers) 
複製代碼

8. Chrome建立圖層的條件

一、3D或透視變換(perspective、transform)CSS屬性
二、使用加速視頻解碼的<video>節點
三、擁有3D(WebGL)上下文或加速的2D上下文的<canvas>節點 
四、混合插件(如Flash) 
五、對本身的opacity作CSS動畫或使用一個動畫webkit變換的元素 
六、擁有加速CSS過濾器的元素 
七、元素有一個包含複合層的後代節點(一個元素擁有一個子元素,該子元素在本身的層裏) 
八、元素有一個z-index較低且包含一個複合層的兄弟元素(換句話說就是該元素在複合層上面渲染)
複製代碼

9. 實戰優化點

一、用translate(重繪)替代top(迴流)改變
二、用opacity替代visibility(重繪) 
三、不要一條一條地修改 DOM 的樣式,預先定義好 class,而後修改 DOM 的className 
四、把 DOM 離線後修改,好比:先把 DOM 給 display:none (有一次迴流),而後你修改100次,而後再把它顯示出來
五、不要把獲取DOM元素的真實位置代碼放在一個循環裏使用,不然會對相關緩衝區進行刷新,最好存到循環外的變量中再去使用
六、不要使用table佈局,可能很小的一個小改動會形成整個 table 的從新佈局(迴流)
七、動畫實現的速度的選擇,動畫速度快(重繪和迴流)的話可能致使頁面性能降低
八、對於動畫新建圖層(例:添加transform CSS屬性)
九、添加 CSS3 樣式啓用 GPU 硬件加速(例:transform: translateZ(0)或transform: translate3d(0, 0, 0))
十、減小對DOM的操做,對DOM操做的代價是高昂的
十一、避免使用出發重繪、迴流的CSS屬性
十二、將重繪、迴流的影響範圍限制在單獨的圖層以內,可是圖層的合成過程比較消耗運算量,圖層不能過多
複製代碼

瀏覽器儲存

1. cookie

  1. 由於HTTP請求無狀態,因此須要cookie去維持客戶端狀態。
  2. 能夠設置過時時間expire
  3. cookie的兩種生成方式及做用
  • http response header中的set-cookie(服務端生成),用於瀏覽器端和服務器端的交互。
  • js中能夠經過document.cookie能夠讀寫cookie(客戶端生成),客戶端自身數據的存儲。
  1. 僅僅做爲瀏覽器存儲。(大小4KB左右,能力被localstorage替代)
  2. 全部相關域名請求都會帶上cookie,有的請求不須要cookie,形成cdn上靜態文件的流量損耗(將cdn域名和主域名獨立開)。
  3. httponly,不容許js進行讀寫,防止攻擊。

2. LocalStorage和SessionStorage

  1. LocalStorage
  • HTML5設計出來專門用於瀏覽器存儲的。(沒有時間限制)
  • 大小爲5M左右。
  • 僅在客戶端使用,不和服務端進行通訊。
  • 接口封裝較好,讀寫、刪除數據方便。
  • 瀏覽器本地緩存方案。
  1. SessionStorage
  • 會話級別的瀏覽器存儲 (瀏覽器一個標籤頁就是一個會話,當籤頁關閉後數據清空)。
  • 大小爲5M左右。
  • 僅在客戶端使用,不和服務端進行通訊。
  • 接口封裝較好,讀寫、刪除數據方便。
  • 適合用於對錶單信息的維護。

3. IndexedDB

  1. IndexedDB 是一種低級API,用於客戶端存儲大量結構化數據。該API使用索引來實現對該數據的高性能搜索。雖然 Web Storage 對於存儲較少許的數據頗有用,但對於存儲更大量的結構化數據來講,這種方法不太有用。IndexedDB提供了一個解決方案。
  2. 爲應用建立離線版本。

4. PWA (Progressive Web Apps)

  1. 簡介
  • PWA (Progressive Web Apps) 是一種 Web App 新模型,並非具體指某一種前沿的技術或者某一個單一的知識點,咱們從英文縮寫來看就能看出來,這是一個漸進式的 Web App,是經過一系列新的 Web 特性,配合優秀的 UI 交互設計,逐步的加強 Web App 的用戶體驗。
  1. 特色
  • 可靠:在沒有網絡的環境中也能提供基本的頁面訪問,而不會出現「未鏈接到互聯網」的頁面。
  • 快速:針對網頁渲染及網絡數據訪問有較好優化。
  • 融入:應用能夠被增長到手機桌面,而且和普通應用同樣有全屏、推送等特性。
  1. 缺點
  • 門檻不低(要求 HTTPS,Service Worker 的 API 比較 low-level)
  • 瀏覽器支持不夠完美(Safari 短時間內不會支持,在 5 年計劃裏提了一嘴)
  • 用戶習慣 (讓用戶習慣於網頁能夠離線工做並非短時間能夠達到的)
  1. 性能檢測工具 Lighthouse,能夠檢測網站是否符合PWA、網站的可靠性、速度等性能優化指標[下載地址]。(https://lavas.baidu.com/doc-lavas/vue/more/downloads/lighthouse_2.1.0_0.zip)

5. Service Worker

  1. 簡介
  • Service Worker 是一個腳本,瀏覽器獨立於當前網頁,將其在後臺運行,爲實現一些不依賴頁面或者用戶交互的特性打開了一扇大門。在將來這些特性將包括推送消息,背景後臺同步,geofencing(地理圍欄定位),但它將推出的第一個首要特性,就是攔截和處理網絡請求的能力,包括以編程方式來管理被緩存的響應。Service Worker只能用於https站點中,非https站點不具有Service Worker能力。
  1. 生命週期

  2. 運用

  • 使用攔截和處理網絡請求的能力,去實現一個離線應用。
  • 使用Service Worker在後臺運行同時能和頁面通訊的能力,去實現大規模後臺數據的處理。
  1. 檢測
  • 查看當前瀏覽器上運行的Service Worker (chrome://inspect/#service-workers)。
  • 查看已註冊的Service Worker (chrome://serviceworker-internals)。

緩存

1. 原理

瀏覽器緩存就是把一個已經請求過的Web資源(如html頁面圖片js數據等)拷貝一份副本儲存在瀏覽器中。緩存會根據進來的請求保存輸出內容的副本。當下一個請求來到的時候,若是是相同的URL,緩存會根據緩存機制決定是直接使用副本響應訪問請求,仍是向源服務器再次發送請求。比較常見的就是瀏覽器會緩存訪問過網站的網頁,當再次訪問這個URL地址的時候,若是網頁沒有更新,就不會再次下載網頁,而是直接使用本地緩存的網頁。只有當網站明確標識資源已經更新,瀏覽器纔會再次下載網頁。

2. 緩存的好處

  1. 減小網絡帶寬消耗
  • 不管對於網站運營者或者用戶,帶寬都表明着金錢,過多的帶寬消耗,只會便宜了網絡運營商。當Web緩存副本被使用時,只會產生極小的網絡流量,能夠有效的下降運營成本。
  1. 下降服務器壓力
  • 給網絡資源設定有效期以後,用戶能夠重複使用本地的緩存,減小對源服務器的請求,間接下降服務器的壓力。同時,搜索引擎的爬蟲機器人也能根據過時機制下降爬取的頻率,也能有效下降服務器的壓力。
  1. 減小網絡延遲,加快頁面打開速度
  • 帶寬對於我的網站運營者來講是十分重要,而對於大型的互聯網公司來講,可能有時由於錢多而真的不在意。那Web緩存還有做用嗎?答案是確定的,對於最終用戶,緩存的使用可以明顯加快頁面打開速度,達到更好的體驗。

3. 瀏覽器請求流程

4. 緩存策略

  1. Expires策略
  • Expires是Web服務器響應消息頭字段,在響應http請求時告訴瀏覽器在過時時間前瀏覽器能夠直接從瀏覽器緩存取數據,而無需再次請求。
  • Expires是HTTP1.0的東西,如今默認瀏覽器均默認使用HTTP1.1,因此它的做用基本忽略。
  • Expires的一個缺點就是返回的到期時間是服務器端的時間,這樣存在一個問題,若是客戶端的時間與服務器的時間相差很大(好比時鐘不一樣步,或者跨時區),那麼偏差就很大,因此在HTTP1.1版開始,使用Cache-Control: max-age=秒替代。
  1. Cache-control策略:Cache-control對應值能夠是publicprivateno-cacheno-storeno-transformmust-revalidateproxy-revalidatemax-ages-maxage
  • 請求Request:

    一、no-cache:不要讀取緩存中的文件,要求向WEB服務器從新請求

    二、no-store:請求和響應都禁止被緩存

    三、max-age:表示當訪問此網頁後的max-age秒內再次訪問不會去服務器請求,其功能與Expires相似,只是 Expires是根據某個特定日期值作比較。一但緩存者自身的時間不許確.則結果可能就是錯誤的,而max-age, 顯然無此問題.。Max-age的優先級也是高於Expires的

    四、max-stale:容許讀取過時時間必須小於max-stale 值的緩存對象

    五、min-fresh:接受其max-age生命期大於其當前時間 跟 min-fresh 值之和的緩存對象

    六、only-if-cached:告知緩存者,我但願內容來自緩存,我並不關心被緩存響應,是不是新鮮的

    七、no-transform:告知代理,不要更改媒體類型,好比jpg,被你改爲png

  • 響應Response:

    一、public: 數據內容皆被儲存起來,就連有密碼保護的網頁也儲存,安全性很低

    二、private:數據內容只能被儲存到私有的cache,僅對某個用戶有效,不能共享

    三、no-cache:能夠緩存,可是隻有在跟WEB服務器驗證了其有效後,才能返回給客戶端

    四、no-store:請求和響應都禁止被緩存

    五、max-age:本響應包含的對象的過時時間

    六、must-revalidate:若是緩存過時了,會再次和原來的服務器肯定是否爲最新數據,而不是和中間的proxy

    七、s-maxage:與max-age的惟一區別是,s-maxage僅僅應用於共享緩存.而不該用於用戶代理的本地緩存等針對單用戶的緩存。另外,s-maxage的優先級要高於max-age

    八、max-stale:容許讀取過時時間必須小於max-stale 值的緩存對象

    九、proxy-revalidate:與must-revalidate相似,區別在於proxy-revalidate要排除掉用戶代理的緩存的。即其規則並不該用於用戶代理的本地緩存上

    十、no-transform:告知代理,不要更改媒體類型,好比jpg,被你改爲png

  1. Last-Modified/If-Modified-Since
  • Last-Modified:標示這個響應資源的最後修改時間。web服務器在響應請求時,告訴瀏覽器資源的最後修改時間。
  • If-Modified-Since:當資源過時時(使用Cache-Control標識的max-age),發現資源具備Last-Modified聲明,則再次向web服務器請求時帶上頭If-Modified-Since表示請求時間。web服務器收到請求後發現有頭If-Modified-Since則與被請求資源的最後修改時間進行比對。若最後修改時間較新,說明資源又被改動過,則響應整片資源內容(寫在響應消息包體內),HTTP 200;若最後修改時間較舊,說明資源無新修改,則響應HTTP 304(無需包體,節省瀏覽),告知瀏覽器繼續使用所保存的cache。
  • 注意:Last-Modified標註的最後修改只能精確到秒級,若是某些文件在1秒鐘之內,被修改屢次的話,它將不能準確標註文件的修改時間。若是某些文件會被按期生成,當有時內容並無任何變化,但Last-Modified卻改變了,致使文件無法使用緩存。有可能存在服務器沒有準確獲取文件修改時間,或者與代理服務器時間不一致等情形。Etag是服務器自動生成或者由開發者生成的對應資源在服務器端的惟一標識符,可以更加準確的控制緩存。Last-Modified與ETag一塊兒使用時,服務器會優先驗證ETag。
  1. Etag/If-None-Match
  • Etag:web服務器響應請求時,告訴瀏覽器當前資源在服務器的惟一標識(生成規則由服務器決定)。Apache中,ETag的值,默認是對文件的索引節(INode),大小(Size)和最後修改時間(MTime)進行Hash後獲得的。
  • If-None-Match:當資源過時時(使用Cache-Control標識的max-age),發現資源具備Etage聲明,則再次向web服務器請求時帶上頭If-None-Match (Etag的值)。web服務器收到請求後發現有頭If-None-Match 則與被請求資源的相應校驗串進行比對,決定返回200或304。
  1. 緩存策略用戶行爲與緩存
相關文章
相關標籤/搜索