vue性能優(yōu)化

文章目錄

1.代碼優(yōu)化

2.項(xiàng)目?jī)?yōu)化

3.其它優(yōu)化

4.總結(jié)

本文主要針對(duì)的是 vue 2.x 版本的性能優(yōu)化,并且從代碼優(yōu)化 和 其他的優(yōu)化去講下在項(xiàng)目開發(fā)時(shí)應(yīng)該注意的優(yōu)化事項(xiàng)。

首先從項(xiàng)目代碼層面方面

1.代碼優(yōu)化

v-if / v-show

這兩個(gè)指令在不同場(chǎng)景的使用下,會(huì)有不同的性能損耗情況,首先簡(jiǎn)單了解下兩者的區(qū)別。

  • v-if 指令在編譯階段就會(huì)編譯成一個(gè)三元運(yùn)算符,通過(guò)條件進(jìn)行渲染。當(dāng)條件的值變化時(shí),會(huì)觸發(fā)對(duì)應(yīng)的組件更新,即會(huì)經(jīng)過(guò) diff 算法, 組件初始化、渲染 vnode、patch等過(guò)程。
  • v-show 指令相比于 v-if 的優(yōu)勢(shì)就是它在更新階段僅僅更新了 DOM 的顯隱,少去了很多性能開銷的操作。但是初始化的時(shí)候會(huì)把所有條件節(jié)點(diǎn)都渲染出來(lái)
<!-- v-if -->
<template>
    <section>
    <p v-if="props.value">Hello World!</p>
    <p v-else>Vue yyds</p>
  </section>
</template>

<!-- v-show -->
<template>
    <section>
    <p v-show="props.value">Hello World!</p>
    <p v-show="!props.value">Vue yyds</p>
  </section>
</template>
  • 使用場(chǎng)景:

初始化階段: v-if 性能優(yōu)于 v-show
頻繁更新階段: v-show 性能優(yōu)于 v-if

v-for 和 v-if

避免把這兩個(gè)指令放在同一個(gè)節(jié)點(diǎn)

因?yàn)?v-for 指令的優(yōu)先級(jí)比 v-if 高,所以兩個(gè)指令混用的話會(huì)導(dǎo)致每次節(jié)點(diǎn)render的結(jié)果都帶上了條件渲染。當(dāng)數(shù)據(jù)量和節(jié)點(diǎn)復(fù)雜的時(shí)候,就會(huì)有明顯的性能差。

當(dāng)我們要循環(huán)節(jié)點(diǎn)和條件判斷的時(shí)候,我們可以先對(duì)數(shù)據(jù)進(jìn)行處理后再進(jìn)行 v-for 渲染,如下例子:

<!-- bad -->
<div v-for="item in list" v-if="item.count > 10" :key="item.id">{{item.name}}</div>

<!-- good -->
<div v-for="item in filters" :key="item.id">{{item.name}}</div>

computed: {
  filters () {
    return this.list.filter(item => item.count > 10)
  }
}

從上面例子不難看出,每個(gè) v-for 節(jié)點(diǎn)處就加了 key 唯一標(biāo)識(shí),這也是提升性能的一個(gè)小點(diǎn)。使用 key 時(shí),vue會(huì)基于 key 的變化重新排列元素順序,并且會(huì)移除 key 不存在的元素。

keep-alive

部分場(chǎng)景可以使用 keep-alive 進(jìn)行組件緩存

keep-alive 包裹的組件在經(jīng)過(guò)渲染后的 vnode 以及 DOM 都會(huì)被緩存起來(lái),然后下次再次渲染該組件的時(shí),直接從緩存中拿到對(duì)應(yīng)的 vnode 和 DOM 并且進(jìn)行渲染,并不需要再走一次組件初始化,render 和 patch 等一系列流程,減少了 script 的執(zhí)行時(shí)間,性能更好。

v-slot:slotName / slot="slotName"

vue 2.6 版本,可以使用 v-slot:slotName 的語(yǔ)法代替 slot="slotName"

  • 舊的寫法在更新時(shí)多了一個(gè)父組件更新的過(guò)程,而新的寫法由于直接更新子組件,就會(huì)更加高效,性能更好,所以推薦始終使用語(yǔ)法 v-slot:slotName
函數(shù)式組件

vue 2.x 的版本,需要DOM層復(fù)用的情況且場(chǎng)景相對(duì)簡(jiǎn)單時(shí),可以用 函數(shù)式組件 代替普通組件

函數(shù)式組件生成的是普通的 vnode,不會(huì)存在遞歸子組件的過(guò)程,所以會(huì)減少一定程度的性能開銷

場(chǎng)景:我在多個(gè)頁(yè)面都復(fù)用了一個(gè)頁(yè)面渲染的組件,不需要一些復(fù)雜的操作,只需要根據(jù)傳參進(jìn)行條件渲染或者循環(huán)渲染等、就可以用如下的例子去進(jìn)行組件的編寫

<!-- 函數(shù)式組件 -->
<template functional>
  <section>
    <div v-if="props.value">Hello World</div>
    <div v-else>Hi~</div>
    <ul>
      <li v-for="item in props.list" :key="item.id">{{item.name}}</li>
    </ul>
  </section>
</template>
子組件拆分

除開代碼維護(hù)的層面,從性能方面,組件的拆分也是有好處的。

  • 因?yàn)関ue 的更新是組件力度,如果組件中有數(shù)據(jù)發(fā)生變化,就會(huì)執(zhí)行 render 函數(shù)生成新的 vnode 和舊的 vnode 進(jìn)行 diff。哪怕這個(gè)數(shù)據(jù)只影響到一個(gè)元素渲染,其他元素也需要在 diff 過(guò)程中進(jìn)行比較。極端情況是假設(shè)這個(gè)大組件里面有個(gè)倒計(jì)時(shí)。
  • 如果組件拆分得當(dāng)?shù)脑挘蟛糠值臄?shù)據(jù)改動(dòng)只會(huì)影響到子組件本身進(jìn)行 diff ==> 渲染。所以合理得對(duì)這種大組件進(jìn)行拆分,應(yīng)用的更新效率會(huì)更高。

例如:

<!-- 拆分前 -->
<template>
  <div :style="{ opacity: number / 300 }">
    <div>{{ heavy() }}</div>
  </div>
</template>

<script>
export default {
  props: ['number'],
  methods: {
    heavy () {
      const n = 100000
      let result = 0
      for (let i = 0; i < n; i++) {
        result += Math.sqrt(Math.cos(Math.sin(42)))
      }
      return result
    },
  },
}
</script>


<!-- 拆分后 -->
<template>
  <div :style="{ opacity: number / 300 }">
    <ChildComp/>
  </div>
</template>

<script>
export default {
  components: {
    ChildComp: {
      methods: {
        heavy () {
          const n = 100000
          let result = 0
          for (let i = 0; i < n; i++) {
            result += Math.sqrt(Math.cos(Math.sin(42)))
          }
          return result
        },
      },
      render (h) {
        return h('div', this.heavy())
      },
    },
  },
  props: ['number'],
}
</script>
響應(yīng)式數(shù)據(jù)優(yōu)化
data的優(yōu)化

vue 在組件實(shí)例初始化的時(shí)候會(huì)對(duì)data進(jìn)行響應(yīng)式處理,能夠減少一個(gè)數(shù)據(jù)就是減少一點(diǎn)點(diǎn)的性能開銷。而且一些常量數(shù)據(jù)不應(yīng)該在data里面進(jìn)行定義,簡(jiǎn)單總結(jié)為以下三點(diǎn):

  • 減少無(wú)用的data數(shù)據(jù)

  • 減少數(shù)據(jù)被observer

  • 數(shù)據(jù)盡量扁平化

局部變量緩存響應(yīng)式數(shù)據(jù)

先直接看對(duì)比代碼

// 優(yōu)化前
// ··········
computed: {
  base () {
    return 42
  },
    result () {
      let result = this.start
      for (let i = 0; i < 1000; i++) {
        result += Math.sqrt(Math.cos(Math.sin(this.base))) + this.base * this.base + this.base + this.base * 2 + this.base * 3
      }
      return result
    },
}

// 優(yōu)化后
// ·········
computed: {
  base () {
    return 42
  },
    result ({ base, start }) {
      let result = start
      for (let i = 0; i < 1000; i++) {
        result += Math.sqrt(Math.cos(Math.sin(base))) + base * base + base + base * 2 + base * 3
      }
      return result
    },
}

優(yōu)化前每次調(diào)用 this.base 的時(shí)候,由于它是個(gè)響應(yīng)式數(shù)據(jù),每次都會(huì)調(diào)用都會(huì)觸發(fā)它的 getter,進(jìn)而執(zhí)行依賴收集等邏輯。

優(yōu)化后先把 this.base 緩存到局部變量,后面重復(fù)調(diào)用的時(shí)候就不會(huì)頻繁的觸發(fā)到 getter 的邏輯處理

computed

計(jì)算屬性是基于它們的響應(yīng)式依賴進(jìn)行緩存的。只在相關(guān)響應(yīng)式依賴發(fā)生改變時(shí)它們才會(huì)重新求值。這就意味著只要 數(shù)據(jù) 還沒有發(fā)生改變,多次訪問(wèn) 計(jì)算屬性會(huì)立即返回之前的計(jì)算結(jié)果,可以極大提升性能。

例如:

<template>
  <div>{{count}}</div>
</template>
<script>
  export default {
    computed: {
      count () {
      let result
      // 復(fù)雜的計(jì)算操作
      return result
      }
    }
  }
</script>

2.項(xiàng)目?jī)?yōu)化

路由懶加載

在vue-router的配置文件里,定義一個(gè)能夠被 Webpack 自動(dòng)代碼分割的異步組件

const Hello = () => import('//hello.vue')
const router = new VueRouter({
  routes: [
    { path: '/hello', component: Hello },
    { path: '/world', component: import('//world.vue') }
  ]
})
組件按需加載

element-ui 為例子,有些項(xiàng)目用ui組件庫(kù)的時(shí)候使用的并不多,可以按需加載適當(dāng)優(yōu)化項(xiàng)目的體積

import {Button} from 'element-ui'

Vue.use(Button)

3.其它優(yōu)化

1.圖片懶加載
2.節(jié)流 / 防抖
3.長(zhǎng)列表的虛擬滾動(dòng)

4.總結(jié)

1.減少?zèng)]必要的渲染機(jī)制
2.減少全量加載,適當(dāng)?shù)膽屑虞d
3.正確的使用vue的每個(gè)api,本身vue這個(gè)框架就對(duì)性能方面做了很多處理,正常使用就不會(huì)出現(xiàn)性能瓶頸

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

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容