翻到一个star,VUE 性能优化给你们分享一下。
业精于勤,行成于思.html
源代码中有个 Static
被注释,没有达到做者的优化效果。 vue
栗子中都分别写在On,Off的对应组件文件中。对比两份代码。 git
Functional components 官方文档.github
<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>
复制代码
<template functional>
<div class="cell">
<div v-if="props.value" class="on"></div>
<section v-else class="off"></section>
</div>
</template>
复制代码
<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>
复制代码
ustbhuangyi (附上原文地址),提出例子中性能问题,用了 heavy
function,应该采用计算属性 computed。这也是使用中,性能优化能够考虑的点,何时该用计算属性。性能优化
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.bash
Instead of using child component splitting, can we use computed property? For example:less
<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 } } } 复制代码
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.ide
<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>
复制代码
<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>
复制代码
<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>
复制代码
<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>
复制代码
<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>
复制代码
<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> 复制代码
<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> 复制代码
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
},
},
}
}
复制代码
最后一个给你们好奇去看代码。渲染10000条数据,一个是creash,优化后的没压力。性能