本文节选转载自
作者:黄轶
链接:https://juejin.cn/post/6922641008106668045
来源:掘金
使用 Non-reactive data
非响应式数据,你可以查看这个在线示例。
优化前代码如下:
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
}
复制代码
还是前面的示例,我们先通过点击 Genterate items
按钮创建 10000 条假数据,然后分别在开启和关闭 Partial reactivity
的情况下点击 Commit items
按钮提交数据,开启 Chrome 的 Performance 面板记录它们的性能,会得到如下结果。
优化前:
优化后:
对比这两张图我们可以看到优化后执行 script
的时间要明显少于优化前的,因此性能体验更好。
之所以有这种差异,是因为内部提交的数据的时候,会默认把新提交的数据也定义成响应式,如果数据的子属性是对象形式,还会递归让子属性也变成响应式,因此当提交数据很多的时候,这个过程就变成了一个耗时过程。
而优化后我们把新提交的数据中的对象属性 data
手动变成了 configurable
为 false
,这样内部在 walk
时通过 Object.keys(obj)
获取对象属性数组会忽略 data
,也就不会为 data
这个属性 defineReactive
,由于 data
指向的是一个对象,这样也就会减少递归响应式的逻辑,相当于减少了这部分的性能损耗。数据量越大,这种优化的效果就会更明显。
其实类似这种优化的方式还有很多,比如我们在组件中定义的一些数据,也不一定都要在 data
中定义。有些数据我们并不是用在模板中,也不需要监听它的变化,只是想在组件的上下文中共享这个数据,这个时候我们可以仅仅把这个数据挂载到组件实例 this
上,例如:
export default {
created() {
this.scroll = null
},
mounted() {
this.scroll = new BScroll(this.$el)
}
}
复制代码
这样我们就可以在组件上下文中共享 scroll
对象了,尽管它不是一个响应式对象。
其实之前在工作中也有同事遇到过类似的问题,后来通过 Object.freeze()
函数提升了一定的性能。
网友评论