介绍
文章链接:https://vuedose.tips/tips/improve-performance-on-large-lists-in-vue-js/
这个网站主打,简洁快速的分享一些关于Vue的tips。每周更新,会发到邮件上。正文是翻译,解读是我自己的相关理解。
正文
在开发过程中,我们经常需要获取一些对象,像users
信息,列表items
,文章信息等等,但是我们不需要去修改这些信息。我们只是把这些信息展示出来,或者放在vuex
中state
里面。如下代码所示
export default {
data: () => ({
users: {}
}),
async created() {
const users = await axios.get("/api/users");
this.users = users;
}
};
Vue默认会对每个数组数据的每一层属性,添加双向数据绑定机制。当数组对象非常庞大时,消耗在这上面的双向数据绑定就越多。
因为,在这种场景下,我们可以通过阻止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]);
解读
来深究一下为什么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]);
会不会触发视图更新。
答案是会。我亲自写demo测试过,重新赋值会触发更新。
是为什么呢?
其实很简单,users
变量是定义在data
中的,在Vue初始化initState
的时候,会遍历data
中的所有属性,添加监听。也就是说我们冻结的是users
里面所有的属性,并没有冻结Vue中data
,所以替换users
会触发双向数据绑定。
翻译或者理解有纰漏的,欢迎大家帮忙指正~