前端性能優(yōu)化

前言
移動互聯(lián)網(wǎng)時代,用戶對于網(wǎng)頁的打開速度要求越來越高。首屏作為直面用戶的第一屏,其重要性不言而喻。優(yōu)化用戶體驗更是我們前端開發(fā)非常需要 focus 的東西之一。

從用戶的角度而言,當我打開一個網(wǎng)頁,我們往往關心的就是我從輸入完網(wǎng)頁地址后到最后能完整地整個頁面的這個過程需要的時間,這個時間越短,用戶體驗越好。所以作為開發(fā)者,也要從輸入url到頁面渲染呈現(xiàn)這個過程中去提升網(wǎng)頁的性能。

所以輸入URL后發(fā)生了什么呢?在瀏覽器中輸入url會經歷域名解析、建立TCP連接、發(fā)送http請求、資源解析等步驟。

http緩存優(yōu)化是網(wǎng)頁性能優(yōu)化的重要一環(huán),這一部分我會在后續(xù)筆記中做一個詳細總結,所以本文暫不多做詳細整理。

一、頁面加載及渲染過程優(yōu)化
瀏覽器渲染流程
首先談談拿到服務端資源后瀏覽器渲染的流程:


image.png
1. 解析 HTML 文件,構建 DOM 樹,同時瀏覽器主進程負責下載 CSS 文件
2. CSS 文件下載完成,解析 CSS 文件成樹形的數(shù)據(jù)結構,然后結合 DOM 樹合并成 RenderObject 樹
3. 布局 RenderObject 樹 (Layout/reflow),負責 RenderObject 樹中的元素的尺寸,位置等計算
4. 繪制 RenderObject 樹 (paint),繪制頁面的像素信息
5. 瀏覽器主進程將默認的圖層和復合圖層交給 GPU 進程,GPU 進程再將各個圖層合成(composite),最后顯示出頁面

CRP(關鍵渲染路徑Critical Rendering Path)優(yōu)化
關鍵渲染路徑是瀏覽器將 HTML、CSS、JavaScript 轉換為在屏幕上呈現(xiàn)的像素內容所經歷的一系列步驟。也就是我們剛剛提到的的的瀏覽器渲染流程。

為盡快完成首次渲染,我們需要最大限度減小以下三種可變因素:

 關鍵資源的數(shù)量: 可能阻止網(wǎng)頁首次渲染的資源。
* 關鍵路徑長度: 獲取所有關鍵資源所需的往返次數(shù)或總時間。
* 關鍵字節(jié): 實現(xiàn)網(wǎng)頁首次渲染所需的總字節(jié)數(shù),等同于所有關鍵資源傳送文件大小的總和。

優(yōu)化 DOM

 刪除不必要的代碼和注釋包括空格,盡量做到最小化文件。
* 可以利用 GZIP 壓縮文件。
* 結合 HTTP 緩存文件。

優(yōu)化 CSSOM
首先,DOM 和 CSSOM 通常是并行構建的,所以 CSS 加載不會阻塞 DOM 的解析 。

然而,由于 Render Tree 是依賴于 DOM Tree 和 CSSOM Tree 的,

所以他必須等待到 CSSOM Tree 構建完成,也就是 CSS 資源加載完成(或者 CSS 資源加載失敗)后,才能開始渲染。因此, CSS 加載會阻塞 Dom 的渲染 。

由此可見,對于 CSSOM 縮小、壓縮以及緩存同樣重要,我們可以從這方面考慮去優(yōu)化。

 減少關鍵 CSS 元素數(shù)量
* 當我們聲明樣式表時,請密切關注媒體查詢的類型,它們極大地影響了 CRP 的性能 。

優(yōu)化 JavaScript
當瀏覽器遇到 script 標記時,會 阻止解析器繼續(xù)操作,直到 CSSOM 構建完畢 ,JavaScript 才會運行并繼續(xù)完成 DOM 構建過程。

async: 當我們在 script 標記添加 async 屬性以后,瀏覽器遇到這個 script 標記時會繼續(xù)解析 DOM,同時腳本也不會被 CSSOM 阻止,即不會阻止 CRP。
* defer: 與 async 的區(qū)別在于,腳本需要等到文檔解析后( DOMContentLoaded 事件前)執(zhí)行,而 async 允許腳本在文檔解析時位于后臺運行(兩者下載的過程不會阻塞 DOM,但執(zhí)行會)。
* 當我們的腳本不會修改 DOM 或 CSSOM 時,推薦使用 async 。
* 預加載 —— preload & prefetch 。
* DNS 預解析 —— dns-prefetch 。

小結

分析并用 **關鍵資源數(shù) 關鍵字節(jié)數(shù) 關鍵路徑長度** 來描述我們的 CRP 。
* 最小化關鍵資源數(shù): 消除它們(內聯(lián))、推遲它們的下載(defer)或者使它們異步解析(async)等等 。
* 優(yōu)化關鍵字節(jié)數(shù)(縮小、壓縮)來減少下載時間 。
* 優(yōu)化加載剩余關鍵資源的順序: 讓關鍵資源(CSS)盡早下載以減少 CRP 長度 。

補充閱讀: 前端性能優(yōu)化之關鍵路徑渲染優(yōu)化

瀏覽器重繪(Repaint)和回流(Reflow)

回流必將引起重繪,重繪不一定會引起回流。

重繪(Repaint)

當頁面中元素樣式的改變并不影響它在文檔流中的位置時(例如:color、background-color、visibility 等),瀏覽器會將新樣式賦予給元素并重新繪制它,這個過程稱為重繪。

回流(Reflow)

當 Render Tree 中部分或全部元素的尺寸、結構、或某些屬性發(fā)生改變時,瀏覽器重新渲染部分或全部文檔的過程稱為回流。

會導致回流的操作:

 頁面首次渲染
* 瀏覽器窗口大小發(fā)生改變
* 元素尺寸或位置發(fā)生改變元素內容變化(文字數(shù)量或圖片大小等等)
* 元素字體大小變化
* 添加或者刪除可見的 DOM 元素
* 激活 CSS 偽類(例如:hover)
* 查詢某些屬性或調用某些方法
* 一些常用且會導致回流的屬性和方法
clientWidth、clientHeight、clientTop、clientLeftoffsetWidth、offsetHeight、offsetTop、offsetLeftscrollWidth、scrollHeight、scrollTop、scrollLeftscrollIntoView()、scrollIntoViewIfNeeded()、getComputedStyle()、
getBoundingClientRect()、scrollTo()

性能影響
回流比重繪的代價要更高。

有時即使僅僅回流一個單一的元素,它的父元素以及任何跟隨它的元素也會產生回流?,F(xiàn)代瀏覽器會對頻繁的回流或重繪操作進行優(yōu)化:瀏覽器會維護一個隊列,把所有引起回流和重繪的操作放入隊列中,如果隊列中的任務數(shù)量或者時間間隔達到一個閾值的,瀏覽器就會將隊列清空,進行一次批處理,這樣可以把多次回流和重繪變成一次。

當你訪問以下屬性或方法時,瀏覽器會立刻清空隊列:

clientWidth、clientHeight、clientTop、clientLeft
offsetWidth、offsetHeight、offsetTop、offsetLeft
scrollWidth、scrollHeight、scrollTop、scrollLeft
width、height
getComputedStyle()
getBoundingClientRect()

因為隊列中可能會有影響到這些屬性或方法返回值的操作,即使你希望獲取的信息與隊列中操作引發(fā)的改變無關,瀏覽器也會強行清空隊列,確保你拿到的值是最精確的。

如何避免
CSS
避免使用 table 布局。
盡可能在 DOM 樹的最末端改變 class。
避免設置多層內聯(lián)樣式。
將動畫效果應用到 position 屬性為 absolute 或 fixed 的元素上。
避免使用 CSS 表達式(例如:calc())。
Javascript
避免頻繁操作樣式,最好一次性重寫 style 屬性,或者將樣式列表定義為 class 并一次性更改 class 屬性。

// 優(yōu)化前
const el = document.getElementById('test');
el.style.borderLeft = '1px';
el.style.borderRight = '2px';
el.style.padding = '5px';
// 優(yōu)化后,一次性修改樣式,這樣可以將三次重排減少到一次重排
const el = document.getElementById('test');
el.style.cssText += '; border-left: 1px ;border-right: 2px; padding: 5px;'

避免頻繁操作 DOM,創(chuàng)建一個 documentFragment,在它上面應用所有 DOM 操作,最后再把它添加到文檔中。
也可以先為元素設置 display: none,操作結束后再把它顯示出來。因為在 display 屬性為 none 的元素上進行的 DOM 操作不會引發(fā)回流和重繪。
避免頻繁讀取會引發(fā)回流/重繪的屬性,如果確實需要多次使用,就用一個變量緩存起來。
對具有復雜動畫的元素使用絕對定位,使它脫離文檔流,否則會引起父元素及后續(xù)元素頻繁回流。
圖片懶加載
圖片懶加載在一些圖片密集型的網(wǎng)站中運用比較多,通過圖片懶加載可以讓一些不可視的圖片不去加載,避免一次性加載過多的圖片導致請求阻塞(瀏覽器一般對同一域名下的并發(fā)請求的連接數(shù)有限制),這樣就可以提高網(wǎng)站的加載速度,提高用戶體驗。

原理
將頁面中的img標簽src指向一張小圖片或者src為空,然后定義data-src(這個屬性可以自定義命名,我才用data-src)屬性指向真實的圖片。src指向一張默認的圖片,否則當src為空時也會向服務器發(fā)送一次請求。可以指向loading的地址。注意,圖片要指定寬高。

<img src="default.jpg" data-src="666.jpg" />

當載入頁面時,先把可視區(qū)域內的img標簽的data-src屬性值負給src,然后監(jiān)聽滾動事件,把用戶即將看到的圖片加載。這樣便實現(xiàn)了懶加載。

實例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <style>
    img {
      display: block;
      margin-bottom: 50px;
      width: 400px;
      height: 400px;
    }
  </style>
</head>
<body>
  <img src="Go.png" data-src="./lifecycle.jpeg" alt="">
  <img src="Go.png" data-src="./lifecycle.jpeg" alt="">
  <img src="Go.png" data-src="./lifecycle.jpeg" alt="">
  <img src="Go.png" data-src="./lifecycle.jpeg" alt="">
  <img src="Go.png" data-src="./lifecycle.jpeg" alt="">
  <img src="Go.png" data-src="./lifecycle.jpeg" alt="">
  <img src="Go.png" data-src="./lifecycle.jpeg" alt="">
  <img src="Go.png" data-src="./lifecycle.jpeg" alt="">
  <img src="Go.png" data-src="./lifecycle.jpeg" alt="">
  <img src="Go.png" data-src="./lifecycle.jpeg" alt="">
  <img src="Go.png" data-src="./lifecycle.jpeg" alt="">
  <script>
    let num = document.getElementsByTagName('img').length;
    let img = document.getElementsByTagName("img");
    let n = 0; //存儲圖片加載到的位置,避免每次都從第一張圖片開始遍歷

    lazyload(); //頁面載入完畢加載可是區(qū)域內的圖片

    window.onscroll = lazyload;

    function lazyload() { //監(jiān)聽頁面滾動事件
      let seeHeight = document.documentElement.clientHeight; //可見區(qū)域高度
      let scrollTop = document.documentElement.scrollTop || document.body.scrollTop; //滾動條距離頂部高度
      for (let i = n; i < num; i++) {
        if (img[i].offsetTop < seeHeight + scrollTop) {
          if (img[i].getAttribute("src") == "Go.png") {
            img[i].src = img[i].getAttribute("data-src");
          }
          n = i + 1;
        }
      }
    }
  </script>

</body>

</html>

事件委托
事件委托其實就是利用JS事件冒泡機制把原本需要綁定在子元素的響應事件(click、keydown……)委托給父元素,讓父元素擔當事件監(jiān)聽的職務。事件代理的原理是DOM元素的事件冒泡。

優(yōu)點:

1. 大量減少內存占用,減少事件注冊。
2. 新增元素實現(xiàn)動態(tài)綁定事件

例如有一個列表需要綁定點擊事件,每一個列表項的點擊都需要返回不同的結果。

傳統(tǒng)寫法:

<ul id="color-list">
    <li>red</li>
    <li>yellow</li>
    <li>blue</li>
    <li>green</li>
    <li>black</li>
    <li>white</li>
  </ul>
  <script>
    (function () {
      var color_list = document.querySelectorAll('li')
      console.log("color_list", color_list)
      for (let item of color_list) {
        item.onclick = showColor;
      }
      function showColor(e) {
        alert(e.target.innerHTML)
        console.log("showColor -> e.target", e.target.innerHTML)
      }
    })();
  </script>

傳統(tǒng)方法會利用for循環(huán)遍歷列表為每一個列表元素綁定點擊事件,當列表中元素數(shù)量非常龐大時,需要綁定大量的點擊事件,這種方式就會產生性能問題。這種情況下利用事件委托就能很好的解決這個問題。

改用事件委托:

<ul id="color-list">
    <li>red</li>
    <li>yellow</li>
    <li>blue</li>
    <li>green</li>
    <li>black</li>
    <li>white</li>
  </ul>
  <script>
    (function () {
      var color_list = document.getElementByid('color-list');
      color_list.addEventListener('click', showColor, true);
      function showColor(e) {
        var x = e.target;
        if (x.nodeName.toLowerCase() === 'li') {
          alert(x.innerHTML);
        }
      }
    })();
  </script>

二、渲染完成后的頁面交互優(yōu)化:
防抖(debounce)/節(jié)流(throttle)
防抖(debounce)
輸入搜索時,可以用防抖debounce等優(yōu)化方式,減少http請求;

這里以滾動條事件舉例:防抖函數(shù) onscroll 結束時觸發(fā)一次,延遲執(zhí)行

function debounce(func, wait) {
  let timeout;
  return function() {
    let context = this; // 指向全局
    let args = arguments;
    if (timeout) {
      clearTimeout(timeout);
    }
    timeout = setTimeout(() => {
      func.apply(context, args); // context.func(args)
    }, wait);
  };
}
// 使用
window.onscroll = debounce(function() {
  console.log('debounce');
}, 1000);

節(jié)流(throttle)
節(jié)流函數(shù):只允許一個函數(shù)在N秒內執(zhí)行一次。滾動條調用接口時,可以用節(jié)流throttle等優(yōu)化方式,減少http請求;

下面還是一個簡單的滾動條事件節(jié)流函數(shù):節(jié)流函數(shù) onscroll 時,每隔一段時間觸發(fā)一次,像水滴一樣

function throttle(fn, delay) {
  let prevTime = Date.now();
  return function() {
    let curTime = Date.now();
    if (curTime - prevTime > delay) {
      fn.apply(this, arguments);
      prevTime = curTime;
    }
  };
}
// 使用
var throtteScroll = throttle(function() {
  console.log('throtte');
}, 1000);
window.onscroll = throtteScroll;

三、Vue相關性能優(yōu)化
如何定位 Vue 應用性能問題
Vue 應用的性能問題可以分為兩個部分,第一部分是運行時性能問題,第二部分是加載性能問題。

和其他 web 應用一樣,定位 Vue 應用性能問題最好的工具是 Chrome Devtool,通過 Performance 工具可以用來錄制一段時間的 CPU 占用、內存占用、FPS 等運行時性能問題,通過 Network 工具可以用來分析加載性能問題。

image.png

更多 Chrome Devtool 使用方式請參考 使用 Chrome Devtool 定位性能問題 的指南

Vue 應用運行時性能優(yōu)化建議

運行時性能主要關注 Vue 應用初始化之后對 CPU、內存、本地存儲等資源的占用,以及對用戶交互的及時響應。

引入生產環(huán)境的 Vue 文件

開發(fā)環(huán)境下,Vue 會提供很多警告來幫你對付常見的錯誤與陷阱。而在生產環(huán)境下,這些警告語句沒有用,反而會增加應用的體積。有些警告檢查還有一些小的 運行時開銷

當使用 webpack 或 Browserify 類似的構建工具時,Vue 源碼會根據(jù) process.env.NODE_ENV 決定是否啟用生產環(huán)境模式,默認情況為開發(fā)環(huán)境模式。在 webpack 與 Browserify 中都有方法來覆蓋此變量,以啟用 Vue 的生產環(huán)境模式,同時在構建過程中警告語句也會被壓縮工具去除。

詳細的做法請參閱 生產環(huán)境部署

使用單文件組件預編譯模板

當使用 DOM 內模板或 JavaScript 內的字符串模板時,模板會在 運行時被編譯為渲染函數(shù) 。通常情況下這個過程已經足夠快了,但 對性能敏感的應用還是最好避免這種用法 。

預編譯模板最簡單的方式就是使用 單文件組件 ——相關的構建設置會自動把預編譯處理好,所以構建好的代碼已經包含了編譯出來的渲染函數(shù)而不是原始的模板字符串。

詳細的做法請參閱 預編譯模板

提取組件的 CSS 到單獨到文件

當使用單文件組件時,組件內的 CSS 會以 <style> 標簽的方式通過 JavaScript 動態(tài)注入。這有一些小小的 運行時開銷 ,將所有組件的 CSS 提取到同一個文件可以避免這個問題,也會讓 CSS 更好地進行壓縮和緩存。

查閱這個構建工具各自的文檔來了解更多:

利用Object.freeze()提升性能

Object.freeze() 可以凍結一個對象,凍結之后不能向這個對象添加新的屬性,不能修改其已有屬性的值,不能刪除已有屬性,以及不能修改該對象已有屬性的可枚舉性、可配置性、可寫性。該方法返回被凍結的對象。

當你把一個普通的 JavaScript 對象傳給 Vue 實例的 data 選項,Vue 將遍歷此對象所有的屬性,并使用 Object.defineProperty 把這些屬性全部轉為 getter/setter,這些 getter/setter 對用戶來說是不可見的,但是在內部它們讓 Vue 追蹤依賴,在屬性被訪問和修改時通知變化。

但 Vue 在遇到像 Object.freeze() 這樣被設置為不可配置之后的對象屬性時,不會為對象加上 setter getter 等數(shù)據(jù)劫持的方法。 參考 Vue 源碼

Object.freeze()### 應用場景

由于 Object.freeze() 會把對象凍結,所以比較適合展示類的場景,如果你的數(shù)據(jù)屬性需要改變,可以重新替換成一個新的 Object.freeze()的對象。

扁平化 Store 數(shù)據(jù)結構

很多時候,我們會發(fā)現(xiàn)接口返回的信息是如下的深層嵌套的樹形結構:

{
  "id": "123",
  "author": {
    "id": "1",
    "name": "Paul"
  },
  "title": "My awesome blog post",
  "comments": [
    {
      "id": "324",
      "commenter": {
        "id": "2",
        "name": "Nicole"
      }
    }
  ]
}

假如直接把這樣的結構存儲在 store 中,如果想修改某個 commenter 的信息,我們需要一層層去遍歷找到這個用戶的信息,同時有可能這個用戶的信息出現(xiàn)了多次,還需要把其他地方的用戶信息也進行修改,每次遍歷的過程會帶來額外的性能開銷。

假設我們把用戶信息在 store 內統(tǒng)一存放成 users[id]這樣的結構,修改和讀取用戶信息的成本就變得非常低。

你可以手動去把接口里的信息通過類似數(shù)據(jù)的表一樣像這樣存起來,也可以借助一些工具,這里就需要提到一個概念叫做 JSON數(shù)據(jù)規(guī)范化(normalize), Normalizr 是一個開源的工具,可以將上面的深層嵌套的 JSON 對象通過定義好的 schema 轉變成使用 id 作為字典的實體表示的對象。

避免持久化 Store 數(shù)據(jù)帶來的性能問題
當你有讓 Vue App 離線可用,或者有接口出錯時候進行災備的需求的時候,你可能會選擇把 Store 數(shù)據(jù)進行持久化,這個時候需要注意以下幾個方面:

持久化時寫入數(shù)據(jù)的性能問題
Vue 社區(qū)中比較流行的 vuex-persistedstate,利用了 store 的 subscribe 機制,來訂閱 Store 數(shù)據(jù)的 mutation,如果發(fā)生了變化,就會寫入 storage 中,默認用的是 localstorage 作為持久化存儲。

也就是說默認情況下每次 commit 都會向 localstorage 寫入數(shù)據(jù),localstorage 寫入是同步的,而且存在不小的性能開銷,如果你想打造 60fps 的應用,就必須避免頻繁寫入持久化數(shù)據(jù)

我們應該盡量減少直接寫入 Storage 的頻率:

* 多次寫入操作合并為一次,比如采用函數(shù)節(jié)流或者將數(shù)據(jù)先緩存在內存中,最后在一并寫入
* 只有在必要的時候才寫入,比如只有關心的模塊的數(shù)據(jù)發(fā)生變化的時候才寫入
  • 避免持久化存儲的容量持續(xù)增長

由于持久化緩存的容量有限,比如 localstorage 的緩存在某些瀏覽器只有 5M,我們不能無限制的將所有數(shù)據(jù)都存起來,這樣很容易達到容量限制,同時數(shù)據(jù)過大時,讀取和寫入操作會增加一些性能開銷,同時內存也會上漲。

尤其是將 API 數(shù)據(jù)進行 normalize 數(shù)據(jù)扁平化后之后,會將一份數(shù)據(jù)散落在不同的實體上,下次請求到新的數(shù)據(jù)也會散落在其他不同的實體上,這樣會帶來持續(xù)的存儲增長。

因此,當設計了一套持久化的數(shù)據(jù)緩存策略的時候,同時應該設計舊數(shù)據(jù)的緩存清除策略,例如請求到新數(shù)據(jù)的時候將舊的實體逐個進行清除。

優(yōu)化無限列表性能

如果你的應用存在非常長或者無限滾動的列表,那么采用 窗口化 的技術來優(yōu)化性能,只需要渲染少部分區(qū)域的內容,減少重新渲染組件和創(chuàng)建 dom 節(jié)點的時間。

vue-virtual-scroll-listvue-virtual-scroller 都是解決這類問題的開源項目。你也可以參考 Google 工程師的文章 Complexities of an Infinite Scroller 來嘗試自己實現(xiàn)一個虛擬的滾動列表來優(yōu)化性能,主要使用到的技術是 DOM 回收、墓碑元素和滾動錨定。

Google 工程師繪制的無限列表設計

image.png

通過組件懶加載優(yōu)化超長應用內容初始渲染性能
上面提到的無限列表的場景,比較適合列表內元素非常相似的情況,不過有時候,你的 Vue 應用的超長列表內的內容往往不盡相同,例如在一個復雜的應用的主界面中,整個主界面由非常多不同的模塊組成,而用戶看到的往往只有首屏一兩個模塊。在初始渲染的時候不可見區(qū)域的模塊也會執(zhí)行和渲染,帶來一些額外的性能開銷。

使用組件懶加載在不可見時只需要渲染一個骨架屏,不需要真正渲染組件

image.png

性能優(yōu)化之組件懶加載: Vue Lazy Component 介紹 ,了解如何做到組件粒度的懶加載。

Vue 應用加載性能優(yōu)化建議

利用服務端渲染(SSR)和預渲染(Prerender)來優(yōu)化加載性能

在一個單頁應用中,往往只有一個 html 文件,然后根據(jù)訪問的 url 來匹配對應的路由腳本,動態(tài)地渲染頁面內容。單頁應用比較大的問題是首屏可見時間過長。

單頁面應用顯示一個頁面會發(fā)送多次請求,第一次拿到 html 資源,然后通過請求再去拿數(shù)據(jù),再將數(shù)據(jù)渲染到頁面上。而且由于現(xiàn)在微服務架構的存在,還有可能發(fā)出多次數(shù)據(jù)請求才能將網(wǎng)頁渲染出來,每次數(shù)據(jù)請求都會產生 RTT(往返時延),會導致加載頁面的時間拖的很長。

服務端渲染、預渲染和客戶端渲染的對比


image.png

這種情況下可以采用服務端渲染(SSR)和預渲染(Prerender)來提升加載性能,這兩種方案,用戶讀取到的直接就是網(wǎng)頁內容,由于少了節(jié)省了很多 RTT(往返時延),同時,還可以對一些資源內聯(lián)在頁面,可以進一步提升加載的性能。

可以參考我們的專欄文章 優(yōu)化向:單頁應用多路由預渲染指南 了解如何利用預渲染進行優(yōu)化。

服務端渲染(SSR)可以考慮使用 Nuxt 或者按照 Vue 官方提供的 Vue SSR 指南 來一步步搭建。

通過組件懶加載優(yōu)化超長應用內容加載性能

在上面提到的超長應用內容的場景中,通過組件懶加載方案可以優(yōu)化初始渲染的運行性能,其實,這對于優(yōu)化應用的加載性能也很有幫助。

組件粒度的懶加載結合異步組件和 webpack 代碼分片,可以保證按需加載組件,以及組件依賴的資源、接口請求等,比起通常單純的對圖片進行懶加載,更進一步的做到了按需加載資源。

使用組件懶加載之前的請求瀑布圖

image.png

使用組件懶加載之后的請求瀑布圖
image.png

使用組件懶加載方案對于超長內容的應用初始化渲染很有幫助,可以減少大量必要的資源請求,縮短渲染關鍵路徑,具體做法請參考我們之前的專欄文章 性能優(yōu)化之組件懶加載: Vue Lazy Component 介紹

總結

上面部分總結了 Vue 應用運行時以及加載時的一些性能優(yōu)化措施,下面做一個回顧和概括:

  • Vue 應用運行時性能優(yōu)化措施

    • 引入生產環(huán)境的 Vue 文件
    • 使用單文件組件預編譯模板
    • 提取組件的 CSS 到單獨到文件
    • 利用Object.freeze()提升性能
    • 扁平化 Store 數(shù)據(jù)結構
    • 合理使用持久化 Store 數(shù)據(jù)
    • 組件懶加載
  • Vue 應用加載性能優(yōu)化措施

    • 服務端渲染 / 預渲染
    • 組件懶加載

文章總結的這些性能優(yōu)化手段當然不能覆蓋所有的 Vue 應用性能問題,我們也會不斷總結和補充其他問題及優(yōu)化措施,希望文章中提到這些實踐經驗能給你的 Vue 應用性能優(yōu)化工作帶來小小的幫助。

四、其他方面優(yōu)化補充

  • webpack模塊打包和JavaScript 壓縮(如gzip壓縮)
  • 利用CDN
  • 按需加載資源
  • 在使用 DOM 操作庫時用上 array-ids
  • 緩存優(yōu)化
  • 避免重定向
  • 啟用 HTTP/2
  • 應用性能分析
  • 使用負載均衡方案
  • 為了更快的啟動時間考慮一下同構
  • 使用索引加速數(shù)據(jù)庫查詢
  • 使用更快的轉譯方案
  • 避免或最小化 JavaScript 和 CSS 的使用而阻塞渲染
  • 用于未來的一個建議:使用 service workers + 流
  • 圖片編碼優(yōu)化,盡量使用svg和字體圖標

結語

有想了解更多的小伙伴可以加Q群鏈接里面看一下,應該對你們能夠有所幫助。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容