Appearance
使用冻结对象提升效率(Vue2)
先看一段代码:
点击load list按钮,往list中添加1000000条数据
vue
<template>
<div id="app">
<button @click="loadList">load list</button>
<h1>list count: {{ list.length }}</h1>
</div>
</template>
<script>
export default {
data() {
return {
list: []
};
},
methods: {
loadList() {
this.list = this.getList();
},
getList() {
const result = [];
for (let i = 0; i < 1000000; i++) {
result.push({
id: i,
name: `name${i}`,
address: {
city: `city${i}`,
province: `province${i}`
}
});
}
return result;
}
}
};
</script>
<style>
#app {
text-align: center;
}
</style>问题:
点击load list按钮之后的结果:

通过录制工具可以看到,js执行时间有4109ms,而渲染并没有花费时间(首先页面没有几个元素,其次计算机执行时间是以纳秒为单位,这里显示0是因为小于了1ms)

了解过vue2响应式原理的都知道,vue2的响应式系统是通过深度遍历数据,利用Object.defineProperty为所有属性添加getter和setter方法,所以时间主要的损耗就在vue将数据转为响应式数据的过程。
但是有些时候,我们并不需要数据响应式,比如纯展示型的列表。那么我们就需要告诉vue,这个时候,就可以使用冻结对象: Object.freeze()
TIP
Object.freeze()静态方法可以使一个对象被冻结。冻结对象可以防止扩展,并使现有的属性不可写入和不可配置。被冻结的对象不能再被更改:不能添加新的属性,不能移除现有的属性,不能更改它们的可枚举性、可配置性、可写性或值,对象的原型也不能被重新指定。freeze() 返回与传入的对象相同的对象。
当我们给vue的数据赋值新数据的时候,vue内部会通过Object.isFrozen进行判断,判断是否为冻结对象,如果是,vue将不再为此数据添加响应式方法。
优化:
vue
<template>
<div id="app">// ...</div>
</template>
<script>
export default {
data() {
return {
list: []
};
},
methods: {
loadList() {
this.list = Object.freeze(this.getList());
},
getList() {
// ...
}
}
};
</script>效果:

可以看到js执行时间已经大幅缩减!!!
总结
虽然我们通过Object.freeze()方法提升了页面的响应速度,但同时我们也失去了数据响应式的功能。所以说优化并不是一概而论的,一定是因地制宜,具体情况具体分析。