使用单文件定义函数式组件
设置functional即表示该组件为一个函数式组件
函数式组件不会有状态,不会有响应式数据,不会有生命周期钩子函数。可以把它当成把普通组件模板中的一部分 DOM 剥离出来,通过函数的方式渲染出来,是一种在 DOM 层面的复用。
优化前:
{{ heavy() }}
优化后:
优化后的方式是把这个耗时任务 heavy 函数的执行逻辑用子组件 ChildComp 封装了,由于 Vue 的更新是组件粒度的,虽然每一帧都通过数据修改导致了父组件的重新渲染,但是 ChildComp 却不会重新渲染,因为它的内部也没有任何响应式数据的变化。所以优化后的组件不会在每次渲染都执行耗时任务,自然执行的 JavaScript 时间就变少了。
优化前:
{{ result }}
优化后:
{{ result }}
主要是优化前后组件的计算属性 result 的实现差异,优化前的组件多次在计算过程中访问 this.base,而优化后的组件会在计算前先用局部变量 base 缓存 this.base,后面则直接访问 base变量。
每次访问 this.base 的时候,由于 this.base 是一个响应式对象,所以会触发它的 getter,进而会执行依赖收集相关逻辑代码
使用v-show复用DOM
优化前的组件代码如下:
优化后的组件代码如下:
用 v-show 指令替代了 v-if 指令来替代组件的显隐
当条件 props.value 的值变化的时候,会触发对应的组件更新,对于 v-if
渲染的节点,由于新旧节点 vnode 不一致,在核心 diff 算法比对过程中,会移除旧的 vnode 节点,创建新的 vnode 节点,那么就会创建新的 Heavy 组件,又会经历 Heavy 组件自身初始化、渲染 vnode、patch 等过程。
因此使用 v-if 每次更新组件都会创建新的 Heavy 子组件,当更新的组件多了,自然就会造成性能压力。
使用 KeepAlive 组件缓存 DOM
优化前:
优化后:
在非优化场景下,每次点击按钮切换路由视图,都会重新渲染一次组件,渲染组件就会经过组件初始化,render、patch 等过程,如果组件比较复杂,或者嵌套较深,那么整个渲染耗时就会很长。
而在使用 KeepAlive 后,被 KeepAlive 包裹的组件在经过第一次渲染后,的 vnode 以及 DOM 都会被缓存起来,然后再下一次再次渲染该组件的时候,直接从缓存中拿到对应的 vnode 和 DOM,然后渲染,并不需要再走一次组件初始化,render 和 patch 等一系列流程,减少了 script 的执行时间,性能更好。
但是使用 KeepAlive 组件并非没有成本,因为它会占用更多的内存去做缓存,这是一种典型的空间换时间优化思想的应用。
使用 Deferred 组件延时分批渲染组件
优化前:
I'm an heavy page
优化后:
I'm an heavy page
Defer 的主要思想就是把一个组件的一次渲染拆成多次,它内部维护了 displayPriority 变量,然后在通过 requestAnimationFrame 在每一帧渲染的时候自增,最多加到 count。然后使用 Defer mixin 的组件内部就可以通过 v-if=“defer(xxx)” 的方式来控制在 displayPriority 增加到 xxx 的时候渲染某些区块了。
使用 Time slicing 时间片切割技术
优化前:
fetchItems ({ commit }, { items }) {
commit('clearItems')
commit('addItems', items)
}
优化后:
fetchItems ({ commit }, { items, splitCount }) {
commit('clearItems')
const queue = new JobQueue()
splitArray(items, splitCount).forEach(
chunk => queue.addJob(done => {
// 分时间片提交数据
requestAnimationFrame(() => {
commit('addItems', chunk)
done()
})
})
)
await queue.start()
}
优化前:
const data = items.map(
item => ({
id: uid++,
data: item,
vote: 0
})
)
优化后:
const data = items.map(
item => optimizeItem(item)
)
function optimizeItem (item) {
const itemData = {
id: uid++,
vote: 0
}
Object.defineProperty(itemData, 'data', {
// Mark as non-reactive
configurable: false,
value: item
})
return itemData
}
优化前:
优化后代码如下: