Vue常用效能優化

WindrunnerMax發表於2020-11-14

Vue常用效能優化

Vue常用的一些優化方式,主要是在構建專案過程需要注意的方面。

編碼優化

避免響應所有資料

不要將所有的資料都放到data中,data中的資料都會增加gettersetter,並且會收集watcher,這樣還佔記憶體,不需要響應式的資料我們可以直接定義在例項上。

<template>
    <view>

    </view>
</template>

<script>
    export default {
        components: {},
        data: () => ({
            
        }),
        beforeCreate: function(){
            this.timer = null;
        }
    }
</script>

<style scoped>
</style>

函式式元件

函式組是一個不包含狀態和例項的元件,簡單的說,就是元件不支援響應式,並且不能通過this關鍵字引用自己。因為函式式元件沒有狀態,所以它們不需要像Vue的響應式系統一樣需要經過額外的初始化,這樣就可以避免相關操作帶來的效能消耗。當然函式式元件仍然會對相應的變化做出響應式改變,比如新傳入新的props,但是在元件本身中,它無法知道資料何時發生了更改,因為它不維護自己的狀態。很多場景非常適合使用函式式元件:

  • 一個簡單的展示元件,也就是所謂的dumb元件。例如buttonspillstagscards等,甚至整個頁面都是靜態文字,比如About頁面。
  • 高階元件,即用於接收一個元件作為引數,返回一個被包裝過的元件。
  • v-for迴圈中的每項通常都是很好的候選項。

區分computed和watch使用場景

computed是計算屬性,依賴其它屬性值,並且computed的值有快取,只有它依賴的屬性值發生改變,下一次獲取computed的值時才會重新計算computed的值。
watch更多的是觀察的作用,類似於某些資料的監聽回撥,每當監聽的資料變化時都會執行回撥進行後續操作。
當我們需要進行數值計算,並且依賴於其它資料時,應該使用computed,因為可以利用computed的快取特性,避免每次獲取值時,都要重新計算。當我們需要在資料變化時執行非同步或開銷較大的操作時,應該使用watch,使用watch選項允許我們執行非同步操作,限制我們執行該操作的頻率,並在我們得到最終結果前,設定中間狀態。

v-for新增key且避免同時使用v-if

  • v-for遍歷必須為item新增key,且儘量不要使用index而要使用唯一id去標識item,在列表資料進行遍歷渲染時,設定唯一key值方便Vue.js內部機制精準找到該條列表資料,當state更新時,新的狀態值和舊的狀態值對比,較快地定位到diff
  • v-for遍歷避免同時使用v-ifv-forv-if優先順序高,如果每一次都需要遍歷整個陣列,將會影響速度。

區分v-if與v-show使用場景

  • 實現方式: v-if是動態的向DOM樹內新增或者刪除DOM元素,v-show是通過設定DOM元素的display樣式屬性控制顯隱。
  • 編譯過程: v-if切換有一個區域性編譯解除安裝的過程,切換過程中合適地銷燬和重建內部的事件監聽和子元件,v-show只是簡單的基於CSS切換。
  • 編譯條件: v-if是惰性的,如果初始條件為假,則什麼也不做,只有在條件第一次變為真時才開始區域性編譯, v-show是在任何條件下都被編譯,然後被快取,而且DOM元素保留。
  • 效能消耗: v-if有更高的切換消耗,v-show有更高的初始渲染消耗。
  • 使用場景: v-if適合條件不太可能改變的情況,v-show適合條件頻繁切換的情況。

長列表效能優化

Vue會通過Object.defineProperty對資料進行劫持,來實現檢視響應資料的變化,然而有些時候我們的元件就是純粹的資料展示,不會有任何改變,我們就不需要Vue來劫持我們的資料,在大量資料展示的情況下,這能夠很明顯的減少元件初始化的時間,可以通過Object.freeze方法來凍結一個物件,一旦被凍結的物件就再也不能被修改了。對於需要修改的長列表的優化大列表兩個核心,一個分段一個區分,具體執行分為:僅渲染視窗可見的資料、進行函式節流、 減少駐留的VNodeVue元件,不使用顯示的子元件slot方式,改為手動建立虛擬DOM來切斷物件引用。

export default {
  data: () => ({
      users: {}
  }),
  async created() {
      const users = await axios.get("/api/users");
      this.users = Object.freeze(users);
  }
};

路由懶載入

Vue是單頁面應用,可能會有很多的路由引入,這樣使用webpcak打包後的檔案很大,當進入首頁時,載入的資源過多,頁面會出現白屏的情況,不利於使用者體驗。如果我們能把不同路由對應的元件分割成不同的程式碼塊,然後當路由被訪問的時候才載入對應的元件,這樣就更加高效。對於Vue路由懶載入的方式有Vue非同步元件、動態importwebpack提供的require.ensure,最常用的就是動態import的方式。

{
  path: "/example",
  name: "example",
  //打包後,每個元件單獨生成一個chunk檔案
  component: () => import("@/views/example.vue")
}

服務端渲染SSR

如果需要優化首屏載入速度並且首屏載入速度是至關重要的點,那麼就需要服務端渲染SSR,服務端渲染SSR其實是優缺點並行的,需要合理決定是否真的需要服務端渲染。

優點

  • 更好的SEO,由於搜尋引擎爬蟲抓取工具可以直接檢視完全渲染的頁面,如果SEO對站點至關重要,而頁面又是非同步獲取內容,則可能需要伺服器端渲染SSR解決此問題。
  • 更快的內容到達時間time-to-content,特別是對於緩慢的網路情況或執行緩慢的裝置,無需等待所有的JavaScript都完成下載並執行,使用者將會更快速地看到完整渲染的頁面,通常可以產生更好的使用者體驗,並且對於那些內容到達時間time-to-content與轉化率直接相關的應用程式而言,伺服器端渲染SSR至關重要。

缺點

  • 開發條件所限,瀏覽器特定的程式碼,只能在某些生命週期鉤子函式lifecycle hook中使用,一些外部擴充套件庫external library可能需要特殊處理,才能在伺服器渲染應用程式中執行。
  • 涉及構建設定和部署的更多要求,與可以部署在任何靜態檔案伺服器上的完全靜態單頁面應用程式SPA不同,伺服器渲染應用程式,通常需要處於Node.js server執行環境。
  • 更大的伺服器端負載,在Node.js中渲染完整的應用程式,顯然會比僅僅提供靜態檔案的server更加大量佔用CPU資源CPU-intensive-CPU密集型,因此如果預料在高流量環境high traffic下使用,需要準備相應的伺服器負載,並明智地採用快取策略。

使用keep-alive元件

當在元件之間切換的時候,有時會想保持這些元件的狀態,以避免反覆重渲染導致的效能等問題,使用<keep-alive>包裹動態元件時,會快取不活動的元件例項,而不是銷燬它們。重新建立動態元件的行為通常是非常有用的,但是在有些情況下我們更希望那些標籤的元件例項能夠被在它們第一次被建立的時候快取下來,此時使用<keep-alive>包裹元件即可快取當前元件例項,將元件快取到記憶體,用於保留元件狀態或避免重新渲染,和<transition>相似它,其自身不會渲染一個DOM元素,也不會出現在元件的父元件鏈中。

<keep-alive>
    <component v-bind:is="currentComponent" class="tab"></component>
</keep-alive>

打包優化

模板預編譯

當使用DOM內模板或JavaScript內的字串模板時,模板會在執行時被編譯為渲染函式,通常情況下這個過程已經足夠快了,但對效能敏感的應用還是最好避免這種用法。預編譯模板最簡單的方式就是使用單檔案元件——相關的構建設定會自動把預編譯處理好,所以構建好的程式碼已經包含了編譯出來的渲染函式而不是原始的模板字串。如果使用webpack,並且喜歡分離JavaScript和模板檔案,可以使用vue-template-loader,其可以在構建過程中把模板檔案轉換成為JavaScript渲染函式。

SourceMap

在專案進行打包後,會將開發中的多個檔案程式碼打包到一個檔案中,並且經過壓縮、去掉多餘的空格、babel編譯化後,最終將編譯得到的程式碼會用於線上環境,那麼這樣處理後的程式碼和原始碼會有很大的差別,當有bug的時候,我們只能定位到壓縮處理後的程式碼位置,無法定位到開發環境中的程式碼,對於開發來說不好調式定位問題,因此sourceMap出現了,它就是為了解決不好調式程式碼問題的,線上上環境則需要關閉sourceMap

配置splitChunksPlugins

Webpack內建了專門用於提取多個Chunk中的公共部分的外掛CommonsChunkPlugin,是用於提取公共程式碼的工具,CommonsChunkPlugin4.0及以後被移除,使用SplitChunksPlugin替代。

使用treeShaking

tree shaking是一個術語,通常用於描述移除JavaScript上下文中的未引用程式碼dead-code,其依賴於ES2015模組系統中的靜態結構特性,例如importexport,這個術語和概念實際上是興起於ES2015模組打包工具rollup

第三方外掛的按需引入

我們在專案中經常會需要引入第三方外掛,如果我們直接引入整個外掛,會導致專案的體積太大,我們可以藉助babel-plugin-component,然後可以只引入需要的元件,以達到減小專案體積的目的,以專案中引入element-ui元件庫為例。

{
  "presets": [["es2015", { "modules": false }]],
  "plugins": [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}

import Vue from 'vue';
import { Button, Select } from 'element-ui';

Vue.use(Button)
Vue.use(Select)

每日一題

https://github.com/WindrunnerMax/EveryDay

參考

https://zhuanlan.zhihu.com/p/121000054
https://www.jianshu.com/p/f372d0e3de80
https://juejin.im/post/6844903887787278349
https://juejin.im/post/6844904189999448071
https://www.lagou.com/lgeduarticle/22278.html
https://www.cnblogs.com/mmzuo-798/p/11778044.html
https://blog.csdn.net/gtlbtnq9mr3/article/details/104889927

相關文章