VUE 9個效能優化祕密?(vue-9-perf-secrets)

Ethan_Ceng發表於2019-04-01

翻到一個star,VUE 效能優化給大家分享一下。
業精於勤,行成於思.

Vue 9 Perf Secrets

栗子

  • Functional components
  • Child component splitting
  • Local variables
  • Reuse DOM with v-show
  • Keep alive(DOM-Reusing Router View)
  • Deferred features
  • Vuex demo

原始碼中有個 Static 被註釋,沒有達到作者的優化效果。

VUE 9個效能優化祕密?(vue-9-perf-secrets)


吃栗子

栗子中都分別寫在On,Off的對應元件檔案中。對比兩份程式碼。

VUE 9個效能優化祕密?(vue-9-perf-secrets)

Functional components

Functional components 官方文件.

FunctionalOff

<template>
  <div class="cell">
    <div v-if="value" class="on"></div>
    <section v-else class="off"></section>
  </div>
</template>

<script>
export default {
  props: ['value'],
}
</script>
複製程式碼

FunctionalOn

<template functional>
  <div class="cell">
    <div v-if="props.value" class="on"></div>
    <section v-else class="off"></section>
  </div>
</template>
複製程式碼

Child component splitting

ChildOff

<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>
複製程式碼

ChildOn

<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>

複製程式碼

Local variables

LocalOff

<template>
  <div :style="{ opacity: start / 300 }">{{ result }}</div>
</template>

<script>
export default {
  props: ['start'],
  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
    },
  },
}
</script>
複製程式碼

LocalOn

<template>
  <div :style="{ opacity: start / 300 }">{{ result }}</div>
</template>

<script>
export default {
  props: ['start'],
  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
    },
  },
}
</script>
複製程式碼

Reuse DOM with v-show

HideOff

<template functional>
  <div class="cell">
    <div v-if="props.value" class="on">
      <Heavy :n="10000"/>
    </div>
    <section v-else class="off">
      <Heavy :n="10000"/>
    </section>
  </div>
</template>
複製程式碼

HideOn

<template functional>
  <div class="cell">
    <div v-show="props.value" class="on">
      <Heavy :n="10000"/>
    </div>
    <section v-show="!props.value" class="off">
      <Heavy :n="10000"/>
    </section>
  </div>
</template>
複製程式碼

Keep alive (DOM-Reusing Router View)

<template>
  <Benchmark title="DOM-Reusing Router View" class="keep-alive">
    <template #toolbar>
      <VueGroup v-model="page">
        <VueGroupButton :value="false">Simple page</VueGroupButton>
        <VueGroupButton :value="true">Heavy page</VueGroupButton>
      </VueGroup>

      <PlayToggle v-model="play"/>
    </template>

    <template #on>
      <keep-alive>
        <router-view/>
      </keep-alive>
    </template>

    <template #off>
      <router-view/>
    </template>
  </Benchmark>
</template>

<script>

export default {
  data () {
    return {
      play: false,
    }
  },

  computed: {
    page: {
      get () {
        return this.$route.name === 'bench-keep-alive-heavy'
      },
      set (value) {
        if (value) {
          this.$router.push({ name: 'bench-keep-alive-heavy' })
        } else {
          this.$router.push({ name: 'bench-keep-alive' })
        }
      },
    },
  },

  watch: {
    play (value) {
      if (value) {
        this.togglePage()
      } else {
        clearTimeout(this.$_timer)
      }
    },
  },

  created () {
    this.count = 300
  },

  methods: {
    togglePage () {
      this.page = !this.page
      if (this.play) {
        this.$_timer = setTimeout(this.togglePage, 2000)
      }
    },
  },
}
</script>

<style lang="stylus" scoped>
.keep-alive
  .router-multi-view
    height 100%

  >>>
    .simple-page,
    .deferred-off
      height 100%
      display flex
      flex-direction column
      align-items center
      padding 40px
      box-sizing border-box

      h2:not(:last-child)
        margin-bottom 24px
</style>
複製程式碼

Deferred features

DeferredOff

<template>
  <div class="deferred-off">
    <VueIcon icon="fitness_center" class="gigantic"/>

    <h2>I'm an heavy page</h2>

    <Heavy v-for="n in 8" :key="n"/>

    <Heavy class="super-heavy" :n="9999999"/>
  </div>
</template>
複製程式碼

DeferredOn

<template>
  <div class="deferred-on">
    <VueIcon icon="fitness_center" class="gigantic"/>

    <h2>I'm an heavy page</h2>

    <template v-if="defer(2)">
      <Heavy v-for="n in 8" :key="n"/>
    </template>

    <Heavy v-if="defer(3)" class="super-heavy" :n="9999999"/>
  </div>
</template>

<script>
import Defer from '@/mixins/Defer'

export default {
  mixins: [
    Defer(),
  ],
}
</script>
複製程式碼

mixin Defer

export default function (count = 10) {
  // @vue/component
  return {
    data () {
      return {
        displayPriority: 0,
      }
    },

    mounted () {
      this.runDisplayPriority()
    },

    methods: {
      runDisplayPriority () {
        const step = () => {
          requestAnimationFrame(() => {
            this.displayPriority++
            if (this.displayPriority < count) {
              step()
            }
          })
        }
        step()
      },

      defer (priority) {
        return this.displayPriority >= priority
      },
    },
  }
}
複製程式碼

Vuex demo

最後一個給大家好奇去看程式碼。渲染10000條資料,一個是creash,優化後的沒壓力。

VUE 9個效能優化祕密?(vue-9-perf-secrets)
VUE 9個效能優化祕密?(vue-9-perf-secrets)

相關文章