經常使用前端性能優化總結大全,體驗飛通常的感受~

前言

性能優化,一直做爲前端的一個熱點問題,做爲一個優秀的前端開發人員,性能優化時必備技能。本文將從減小http請求次數、減小單次請求資源大小、渲染優化、資源加載優化等四個大方向,下分諸多小方向,全面總結經常使用前端優化方法。 (內容較多請看目錄)css

減小http請求次數

1.瀏覽器緩存策略

瀏覽器緩存機制有四個方面,它們按照獲取資源時請求的優先級依次排列以下:
html

  • Memory Cache:是指存在內存中的緩存。從優先級上來講,它是瀏覽器最早嘗試去命中的一種緩存。從效率上來講,它是響應速度最快的一種緩存。瀏覽器秉承的是「節約原則」,咱們發現,Base64格式的圖片,幾乎永遠能夠被塞進memory cache,這能夠視做瀏覽器爲節省渲染開銷的「自保行爲」;此外,體積不大的JS、CSS文件,也有較大地被寫入內存的概率——相比之下,較大的JS、CSS文件就沒有這個待遇了,內存資源是有限的,它們每每被直接甩進磁盤。
  • Service Worker Cache:是一種獨立於主線程以外的Javascript線程。它脫離於瀏覽器窗體,所以沒法直接訪問DOM。這樣獨立的個性使得 Service Worker的「我的行爲」沒法干擾頁面的性能,這個「幕後工做者」能夠幫咱們實現離線緩存、消息推送和網絡代理等功能。咱們藉助 Service worker 實現的離線緩存就稱爲Service Worker Cache。
  • HTTP Cache:它又分爲強緩存和協商緩存。優先級較高的是強緩存,在命中強緩存失敗的狀況下,纔會走協商緩存。
      強緩存是利用http頭中的Expires和Cache-Control兩個字段來控制的。強緩存中,當請求再次發出時,瀏覽器會根據其中的 expires 和 cache-control判斷目標資源是否「命中」強緩存,若命中則直接從緩存中獲取資源,不會再與服務端發生通訊。
      協商緩存依賴於服務端與瀏覽器之間的通訊。協商緩存機制下,瀏覽器須要向服務器去詢問緩存的相關信息,進而判斷是從新發起請求、下載完整的響應,仍是從本地獲取緩存的資源。若是服務端提示緩存資源未改動(Not Modified),資源會被重定向到瀏覽器緩存,這種狀況下網絡請求對應的狀態碼是304。
  • Push Cache:是指 HTTP2 在 server push 階段存在的緩存。Push Cache 是緩存的最後一道防線。瀏覽器只有在 Memory Cache、HTTP Cache 和 Service Worker Cache 均未命中的狀況下才會去詢問 Push Cache。
      Push Cache 是一種存在於會話階段的緩存,當 session 終止時,緩存也隨之釋放。不一樣的頁面只要共享了同一個 HTTP2 鏈接,那麼它們就能夠共享同一個 Push Cache。

2.CDN

  CDN 的核心點有兩個,一個是緩存,一個是回源。
  「緩存」就是說咱們把資源 copy一份到CDN服務器上這個過程,「回源」就是說CDN發現本身沒有這個資源(通常是緩存的數據過時了),轉頭向根服務器(或者它的上層服務器)去要這個資源的過程。
  CDN每每被用來存放靜態資源。所謂「靜態資源」,就是像 JS、CSS、圖片等不須要業務服務器進行計算即得的資源。用戶能夠從一個較優的服務器獲取數據,從而達到快速訪問,並減小源站負載壓力的目的。
  另外,CDN的域名必須和主業務服務器的域名不同,要不,同一個域名下面的Cookie各處跑,浪費了性能流量的開銷,CDN域名放在不一樣的域名下,能夠完美地避免了沒必要要的 Cookie 的出現!前端

3.圖片處理

  • sprite雪碧圖:CSS雪碧圖是之前很是流行的技術,把網站上的一些圖片整合到一張單獨的圖片中,能夠減小網站的HTTP請求數量,可是當整合圖片比較大時,一次加載比較慢。隨着字體圖片、SVG圖片的流行,該技術漸漸退出了歷史舞臺。
  • base64圖片編碼:將圖片的內容以Base64格式內嵌到HTML中,能夠減小HTTP請求數量。可是,因爲Base64編碼用8位字符表示信息中的6個位,因此編碼後大小大約比原始值擴大了 33%
  • 字體圖標:字體圖標經過本身規定字體的unicode編碼,找到文件後根據unicode碼去查找繪製外形,以文字的形式代替圖片。

4.文件合併

將公共的js、css樣式合併爲一個大文件。
根據不一樣頁面的需求單獨合併所需js、css文件。web

5.減小重定向

  儘可能避免使用重定向,當頁面發生了重定向,就會延遲整個HTML文檔的傳輸。在HTML文檔到達以前,頁面中不會呈現任何東西,也沒有任何組件會被下載,下降了用戶體驗。
  若是必定要使用重定向,如http重定向到https,要使用301永久重定向,而不是302臨時重定向。由於,若是使用302,則每一次訪問http,都會被重定向到https的頁面。而永久重定向,在第一次從http重定向到https以後,每次訪問http,會直接返回https的頁面。瀏覽器

減小單次請求資源大小

6.css壓縮、圖片壓縮、gzip壓縮、js混淆等

css壓縮,就是進行簡單的壓縮,壓縮空白等。
圖片壓縮,主要也是減少體積,在不影響觀感的前提下,能夠刪除一些可有可無的色彩。另外可使用webp格式圖片。
gzip壓縮主要是針對html文件來講的,它能夠將html中重複的部分進行一個打包,屢次複用。
js混淆能夠有簡單的壓縮(將空白字符刪除)、醜化(將一些變量縮小)、或者對js進行混淆加密。緩存

渲染優化

7.優化css選擇符

CSS 選擇符是從右到左進行匹配的,好比 #myul li {}實際開銷至關高。所以須要對選擇符進行優化,主要有以下幾方面:性能優化

  • 避免使用通配符*,只對須要用到的元素進行選擇。
  • 少用標籤選擇器。若是能夠,用類選擇器替代。錯誤:#dataList li{} 正確:.dataList{}
  • 關注能夠經過繼承實現的屬性,避免重複匹配重複定義。
  • 不要多此一舉,id 和 class 選擇器不該該被多餘的標籤選擇器拖後腿。錯誤:.dataList#title 正確:#title
  • 減小嵌套。後代選擇器的開銷是最高的,所以咱們應該儘可能將選擇器的深度降到最低(最高不要超過三層),儘量使用類來關聯每個標籤元素。

8.減小回流和重繪次數

  • 迴流:當咱們對 DOM 的修改引起了 DOM 幾何尺寸的變化(好比修改元素的寬、高或隱藏元素等)時,瀏覽器須要從新計算元素的幾何屬性(其餘元素的幾何屬性和位置也會所以受到影響),而後再將計算的結果繪製出來。這個過程就是迴流(也叫重排)。
  • 重繪:當咱們對 DOM 的修改致使了樣式的變化、卻並未影響其幾何屬性(好比修改了顏色或背景色)時,瀏覽器不需從新計算元素的幾何屬性、直接爲該元素繪製新的樣式(跳過了上圖所示的迴流環節)。這個過程叫作重繪。

重繪不必定致使迴流,迴流必定會致使重繪。bash

9.減小DOM操做

從上面能夠知道,DOM改變容易引發迴流和重繪,所以咱們要減小DOM操做。 例子剖析,以下代碼:服務器

for(var count=0;count<10000;count++){ 
  document.getElementById('container').innerHTML+='<span>我是一個小測試</span>'  //咱們每一次循環都調用 DOM 接口從新獲取了一次 container 元素,額外開銷
} 
複製代碼

進化一babel

// 只獲取一次container
let container = document.getElementById('container')
for(let count=0;count<10000;count++){ 
  container.innerHTML += '<span>我是一個小測試</span>'
} 
複製代碼

進化二
考慮JS 的運行速度,比 DOM 快得多這個特性。咱們減小 DOM 操做的核心思路,就是讓 JS 去給 DOM 分壓。

//減小沒必要要的DOM更改
let container = document.getElementById('container')
let content = ''
for(let count=0;count<10000;count++){ 
  // 先對內容進行操做
  content += '<span>我是一個小測試</span>'
} 
// 內容處理好了,最後再觸發DOM的更改
container.innerHTML = content
複製代碼

進化三
在 DOM Fragment 中,DocumentFragment 接口表示一個沒有父級文件的最小文檔對象。它被當作一個輕量版的 Document 使用,用於存儲已排好版的或還沒有打理好格式的XML片斷。由於 DocumentFragment 不是真實 DOM 樹的一部分,它的變化不會引發 DOM 樹的從新渲染的操做(reflow),且不會致使性能等問題。

let container = document.getElementById('container')
// 建立一個DOM Fragment對象做爲容器
let content = document.createDocumentFragment()
for(let count=0;count<10000;count++){
  // span此時能夠經過DOM API去建立
  let oSpan = document.createElement("span")
  oSpan.innerHTML = '我是一個小測試'
  // 像操做真實DOM同樣操做DOM Fragment對象
  content.appendChild(oSpan)
}
// 內容處理好了,最後再觸發真實DOM的更改
container.appendChild(content)
複製代碼

進化四
當涉及到過萬調數據進行渲染,並且要求不卡住畫面,如何解決? 如何在不卡住頁面的狀況下渲染數據,也就是說不能一次性將幾萬條都渲染出來,而應該一次渲染部分 DOM,那麼就能夠經過 requestAnimationFrame 來每 16 ms 刷新一次。

setTimeout(() => {
        // 插入十萬條數據
        const total = 100000
        // 一次插入 20 條,若是以爲性能很差就減小
        const once = 20
        // 渲染數據總共須要幾回
        const loopCount = total / once
        let countOfRender = 0
        let ul = document.querySelector('ul')
        function add() {
          // 優化性能,插入不會形成迴流
          const fragment = document.createDocumentFragment()
          for (let i = 0; i < once; i++) {
            const li = document.createElement('li')
            li.innerText = Math.floor(Math.random() * total)
            fragment.appendChild(li)
          }
          ul.appendChild(fragment)
          countOfRender += 1
          loop()
        }
        function loop() {
          if (countOfRender < loopCount) {
            window.requestAnimationFrame(add)
          }
        }
        loop()
      }, 0)
複製代碼

10.使用事件委託

  事件委託是指將事件監聽器註冊在父級元素上,因爲子元素的事件會經過事件冒泡的方式向上傳播到父節點,所以,能夠由父節點的監聽函數統一處理多個子元素的事件。利用事件委託,能夠減小內存使用,提升性能及下降代碼複雜度。

11.節流和防抖

  當用戶進行滾動,觸發scroll事件,用戶的每一次滾動都將觸發咱們的監聽函數。函數執行是吃性能的,頻繁地響應某個事件將形成大量沒必要要的頁面計算。所以,咱們須要針對那些有可能被頻繁觸發的事件做進一步地優化。節流與防抖就頗有必要了!

  • 函數節流: 頻繁觸發,但只在特定的時間內才執行一次代碼
  • 函數防抖: 頻繁觸發,但只在特定的時間內沒有觸發執行條件才執行一次代碼 //防抖函數
//節流函數
function throttle(fn,time){
	var last = 0;
	return function(){
		var context = this;
		var now = Date.now();
		if (now - last >= time){
			fn.apply(this, arguments);
			last = now;
		}
	};
}
//防抖函數
function debounce(fn, time){
	return function(){
		var context = this;
		clearTimeout(timeId);
		timeId = setTimeout(function(){
			fn.apply(context, arguements);
		}, time);
	};
}
複製代碼

資源加載優化

12.資源預加載和懶加載

  • 懶加載會延遲加載資源或符合某些條件時才加載某些資源。
  • 預加載是提早加載用戶所需的資源,加速頁面的加載速度,保證良好的用戶體驗。

資源懶加載和資源預加載都是一種錯峯操做,在瀏覽器忙碌的時候不作操做,瀏覽器空間時,再加載資源,優化了網絡性能。

13.css、js文件引用位置優化

  • CSS文件放在head中,先外鏈,後本頁。
  • JS文件放在body底部,先外鏈,後本頁。
  • body中間儘可能不寫style標籤和script標籤。
  • 處理頁面、處理頁面佈局的JS文件放在head中,如babel-polyfill.js文件、flexible.js文件。
相關文章
相關標籤/搜索