Turn to a star, VUE performance optimization to share with you. Practice makes perfect and success depends on thought.
Vue 9 Perf Secrets
- GitHub.
- Demo
chestnuts
- Functional components
- Child component splitting
- Local variables
- Reuse DOM with v-show
- Keep alive(DOM-Reusing Router View)
- Deferred features
- Vuex demo
There is a Static comment in the source code, which does not achieve the author’s optimization effect.
Eat chestnuts
Both are written in the corresponding component files of On and Off. Compare two pieces of code.
Functional components
Functional Components official documentation.
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>
Copy the code
FunctionalOn
<template functional>
<div class="cell">
<div v-if="props.value" class="on"></div>
<section v-else class="off"></section>
</div>
</template>
Copy the code
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>
Copy the code
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>
Copy the code
About an Issue
Ustbhuangyi, which presents the performance problem in the example, uses heavy Function and should use computed property computed. This is also the point where performance optimization can be considered in use, when to use computed properties.
First, thanks for the awesome Project!
In the Child Component Splitting Demo, the root cause of the performance problem is that we use heavy function during render, it will also be called when the component render.
Instead of using child component splitting, can we use computed property? For example:
<template> <div :style="{ opacity: number / 300 }"> <div>{{ heavy }}</div> </div> </template> <script> export default { props: ['number'], computed: { heavy () { const n = 100000 let result = 0 for (let i = 0; i < n; i++) { result += Math.sqrt(Math.cos(Math.sin(42))) } return result } } } Copy the code
Because create a child component will have some extra overhead, so computed property here is better ? Computed property will use cache if it’s dependencies not change, and I think we should use computed property as much as possible other than method, unless in some special cases.
Local variables
LocalOff
<template>
<div :style="{ opacity: start / 300 }">{{ result }}</div>
</template>
<script>
export default {
props: ['start'],
computed: {
base () {
return42},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>
Copy the code
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>
Copy the code
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>
Copy the code
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>
Copy the code
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.pageif (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>
Copy the code
Deferred features
DeferredOff
<template>
<div class="deferred-off">
<VueIcon icon="fitness_center" class="gigantic"/>
<h2>I'm an heavy page
Copy the code
DeferredOn
<template>
<div class="deferred-on">
<VueIcon icon="fitness_center" class="gigantic"/>
<h2>I'm an heavy page
@/mixins/Defer' export default { mixins: [ Defer(), ], } Copy the code
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
},
},
}
}
Copy the code
Vuex demo
The last one is for the curious to look at the code. Render 10000 data, one is Creash, optimized without pressure.