通常我们在应用中会请求一些列表数据,比如说用户列表、商品列表、文章列表等等......
而且有时候,我们并不会去修改这些请求回来的列表数据,而只是单纯地去展示它们,或者是把它们保存在全局状态管理器里面(又称之为 Vuex)。请求数据列表的示意代码如下所示:
export default {
data: () => ({
users: {}
}),
async created() {
const users = await axios.get("/api/users");
this.users = users;
}
};
Vue 在默认情况下,会将数组this.users中的,所有对象的第一层属性设置为响应式数据。
这对于大型的对象数组来说,性能成本非常的高。没错,的确有时候列表数据是有分页的,但总会有一些情况下,是没有进行分页,继而在前端展示的。
一个实际的例子就是谷歌地图的标记点 markers 列表数据,这就是一个拥有很多对象的大型数组。
所以,在一些特定的情况下,如果我们能够阻止 Vue 将这些列表数据设置为响应式的,那么我们就可以为项目带来一些性能上的提升。实际上我们就是可以做到的,通过用Object.freeze方法,将获取到的列表数据在赋值给组件之前,进行冻结:
export default {
data: () => ({
users: {}
}),
async created() {
const users = await axios.get("/api/users");
this.users = Object.freeze(users);
}
};
记住,同样地可以应用到 Vuex 实践中:
const mutations = {
setUsers(state, users) {
state.users = Object.freeze(users);
}
};
顺便说一下,如果你确实有需要去修改请求得到的列表数据,那么你仍然可以通过创建一个新的数组来实现。举个例子,给原列表数据添加一个同类型元素,可以这么操作:
state.users = Object.freeze([...state.users, user]);
来源:https://juejin.cn/post/6844903766982934535
来深究一下为什么Object.freeze()方法可以做到阻止Vue添加双向数据绑定机制
大家应该都知道Vue是通过Object.defineProperty()来修改属性描述符中的setter和getter的,在getter中收集依赖,在setter的时候触发依赖。
在ES5开始,所有的属性都有了属性描述符。决定是否可以修改一个属性的描述符有两个:
是Writable:决定是否可以修改属性的值;
另一个是Configurable:决定是否可以使用Object.defineProperty()来修改属性描述符,并且也会禁止删除这个属性;
当这两个描述符同时为false时,意味着这个属性完全是一个常量,Vue不能通过Object.defineProperty()来添加双向数据绑定。收集不了依赖,也就做不了双向数据绑定,就少添加很多watcher实例。
执行Object.freeze()会执行Object.seal()并吧所有的属性的writable设置成false。
Object.seal()则会调用Object.preventExtensions()并把configurable设为false。
Object.preventExtensions()则会禁止对象添加新的属性。
最后还有一个疑问,state.users = Object.freeze([...state.users, user]);会不会触发视图更新。
答案是会。users变量是定义在data中的,在Vue初始化initState的时候,会遍历data中的所有属性,添加监听。也就是说我们冻结的是users里面所有的属性,并没有冻结Vue中data,所以替换users会触发双向数据绑定
来源:https://www.jianshu.com/p/56168a779849