前端性能優化+代碼示例

前言

現在確實有好多性能優化方面的文章,但好多都只是文字講解,馬上下班了,抽點時間總結總結。

前端性能優化的原則其實就是更好的用戶體驗,具體實現的目標大體有兩個:

  1. 合理使用內存或緩存,減少請求;
  2. 減少CPU或者GPU的計算,達到更快的展現。

前端在性能優化的方向大體有兩個:

  1. 減少頁面體積,提升網絡加載
  2. 優化頁面渲染

正文

一.減少頁面體積,提升網絡加載

1、靜態資源的壓縮合並(JS 代碼壓縮合並、CSS 代碼壓縮合並、雪碧圖)

  1. 壓縮是爲了減小文件體積,減輕網絡負載,達到更快的下載;
  2. 合併和雪碧圖都是爲了減少文件的請求次數,但不是合併的就一個比沒有合併時加載快,要看合併之後的體積,若文件合併後太大了也不太利於性能優化,所以在實際的項目中要做好權衡。

2、靜態資源緩存(資源名稱加 MD5 戳)

      可以通過鏈接名稱控制緩存:通過前端構建工具爲打包的文件添加md5後綴,這樣當打包上線時請求的鏈接發生改變,這樣可以防止由於緩導致靜態資源更新失效;

3、 使用 CDN 讓資源加載更快

二.優化頁面渲染

1、CSS 放前面,JS 放後面

  1. 瀏覽器在渲染解析過程中,若遇到<link href="..."><script src="...">這種外鏈加載 CSS 和 JS 的標籤,瀏覽器會異步下載並解析執行。CSS放在頭部是爲了讓瀏覽器儘早解析執行Css文件,渲染出頁面的樣式,若放在底部會出現渲染卡頓的情況,影響性能和體驗。
  2. 而當渲染過程中遇到script標籤時就會執行JS代碼,從阻塞頁面渲染,因爲瀏覽器渲染和 JS 執行共用一個線程,而且這裏必須是單線程操作,多線程會產生渲染 DOM 衝突。所以要將JS放在底部,等到頁面渲染完成之後再去解析執行js,保證用戶體驗性。因爲瀏覽器渲染和 JS 執行共用一個線程,而且這裏必須是單線程操作,多線程會產生渲染 DOM 衝突。
  3. 另外,JS 執行如果涉及 DOM 操作,得等待 DOM 解析完成才行,JS 放在底部執行時,HTML 肯定都解析成了 DOM 結構。JS 如果放在 HTML 頂部,JS 執行的時候 HTML 還沒來得及轉換爲 DOM 結構,可能會報錯。

2、懶加載(圖片懶加載、下拉加載更多)

先將src賦值成一個通用的預覽圖,下拉時候再動態賦值成正式的圖片。如下,preview.png是預覽圖片,比較小,加載很快,而且很多圖片都共用這個preview.png,加載一次即可。待頁面下拉,圖片顯示出來時,再去替換src爲data-src的值。(data-開頭的屬性瀏覽器渲染的時候會忽略掉,提高渲染性能)

<img src="preview.png" data-src="realImg.png"/>

3、減少DOM 查詢,對 DOM 查詢做緩存

    // 只查詢一個 DOM ,緩存在 pList 中了
    var pList = document.getElementsByTagName('p')  
    for (var i = 0; i < pList.length; i++) {
    }
    // 每次循環,都會查詢 DOM ,耗費性能
    for (var i = 0; i < document.getElementsByTagName('p').length; i++) {
    }

4、減少DOM 操作,多個操作儘量合併在一起執行(DocumentFragment)

DOM 操作是非常耗費性能的,因此插入多個標籤時,先插入 Fragment 然後再統一插入 DOM。因爲Fragment文檔片段存在於內存中,並不在DOM樹中,所以將子元素插入到文檔片段時不會引起頁面迴流。

    var listNode = document.getElementById('list')
    // 要插入 10 個 li 標籤
    var frag = document.createDocumentFragment();
    var i, li;
    for(i = 0; i < 10; i++) {
        li = document.createElement("li");
        li.innerHTML = "List item " + i;
        frag.appendChild(li);  //先放在 frag 中,最後一次性插入到 DOM 結構中。
    }
    listNode.appendChild(frag);

5、事件節流

在開發過程中會遇到頁面一些頻繁觸發的事件,比如mouseover、scroll、resize等事件。一秒可以執行很多次,這樣會造成嚴重的頁面性能問題,導致頁面c出現卡頓甚至瀏覽器崩潰。因此我們需要對事件進行節流,簡單的說就是控制其執行的次數。這裏就涉及到了常用到的js的節流和防抖功能實現。
       1.防抖(debounce):在事件被觸發n秒後再執行回調,如果在這n秒內又被觸發,則重新計時。

    function debounce(fn, delay) {
        // 定時器,用來 setTimeout
        var timer
        // 返回一個函數,這個函數會在一個時間區間結束後的 delay 毫秒時執行 fn 函數
        return function () {
            // 保存函數調用時的上下文和參數,傳遞給 fn
            var context = this
            var args = arguments
            // 每次這個返回的函數被調用,就清除定時器,以保證不執行 fn
            timer && clearTimeout(timer)
            // 當返回的函數被最後一次調用後(也就是用戶停止了某個連續的操作),
            // 再過 delay 毫秒就執行 fn
            timer = setTimeout(function () {
                fn.apply(context, args)
            }, delay)
        }
    }

     2、節流(throttle):規定一個單位時間,在這個單位時間內,只能有一次觸發事件的回調函數執行,如果在同一個單位時間內某事件被觸發多次,只有一次能生效。

    function throttle(fn, threshhold) {
        // 記錄上次執行的時間
        var last
        // 定時器
        var timer
        // 默認間隔爲 250ms
        threshhold || (threshhold = 250)
        // 返回的函數,每過 threshhold 毫秒就執行一次 fn 函數
        return function () {
            // 保存函數調用時的上下文和參數,傳遞給 fn
            var context = this
            var args = arguments
            var now = +new Date()
            // 如果距離上次執行 fn 函數的時間小於 threshhold,那麼就放棄
            // 執行 fn,並重新計時
            if (last && now < last + threshhold) {
                timer && clearTimeout(timer)
                // 保證在當前時間區間結束後,再執行一次 fn
                timer = setTimeout(function () {
                    last = now
                    fn.apply(context, args)
                }, threshhold)
            // 在時間區間的最開始和到達指定間隔的時候執行一次 fn
            } else {
                last = now
                fn.apply(context, args)
            }
        }
    }

6、儘早執行操作(DOMContentLoaded) 

    window.addEventListener('load', function () {
        // 頁面的全部資源加載完纔會執行,包括圖片、視頻等
    })
    document.addEventListener('DOMContentLoaded', function () {
        // DOM 渲染完即可執行,此時圖片、視頻還可能沒有加載完
    })
    $(document).ready({function () {
        // 同DOMContentLoaded
    })

7、使用 預渲染 或者 SSR後端渲染,數據直接輸出到 HTML 中,減少瀏覽器使用 JS 模板渲染頁面 HTML 的時間 (如Vue SSR),同時也有利於網站的SEO。

最後

感謝各位的閱讀,如有問題麻煩及時指正出來。

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