记一次比较Vue2和Vue3响应式原理和性能差异
共 5005字,需浏览 11分钟
·
2021-03-02 12:48
关注公众号 前端人,回复“加群”
添加无广告优质学习群
写在前面
Vue响应式原理是数据驱动视图的核心,它能够自动帮助开发者监听数据的变化,最终触发视图更新。它是Vue的渲染更新过程的核心。
那么了解这一部分的原理至关重要,这篇文章就结合vue2和vue3响应式来做一个对比,既明白了响应式原理的实现,又对比了二者在性能上的差异~
需要了解的api
这篇文章不是零基础,需要对一些基础api有一定的了解,那么这里给出这些api的官方文档,供大家参考学习:
vue2响应式原理 Object.defineProperty vue3响应式原理 Proxy Reflect
准备一个原始对象数据
为了做这个实验,我使用同一个数据对象来分别做vue2和vue3的示例:注意这个data数据从最外层花括弧到最里层总共8个层级,你可以数一下。
const data = {
username: 'tom',
profile: {
city: 'beijing',
a: {
b: 12,
c: {
d: 23
}
}
}
}
接下来我分别写点代码对这个数据做响应式处理:
vue2
const data = {
username: "tom",
profile: {
city: "beijing",
a: {
b: 12,
c: {
d: 23,
},
},
},
};
function observe(data) {
console.log(1);
if (typeof data !== "object" || data == null) {
return data;
}
for (const key in data) {
defineReactive(data, key, data[key]);
}
}
function defineReactive(target, key, val) {
observe(val);
Object.defineProperty(target, key, {
get() {
console.log(`get ${key}`);
return val;
},
set(newValue) {
console.log(`set ${key}`);
if (newValue !== val) {
observe(newValue);
val = newValue;
}
},
});
}
observe(data);
console.log(data);
打印的结果如下:
从图中可以清晰的看到总共打印了8次1,也就是说observe一共执行了8次;由此可见vue2是一次递归到底的来实现响应式的,好接下来看看vue3:
vue3
function observe(data) {
console.log(1);
if (typeof data !== "object" || data == null) {
return data;
}
const p = new Proxy(data, {
get(target, key, receiver) {
console.log(`get ${key}`);
const result = Reflect.get(data, key, receiver);
// 当获取值的是时候 再设置响应式
return observe(result);
},
set(target, key, val, receiver) {
console.log(`set ${key}`);
const result = Reflect.set(target, key, val, receiver);
return result;
},
});
return p;
}
const data = {
username: "tom",
profile: {
city: "beijing",
a: {
b: 12,
c: {
d: 23,
},
},
},
};
const p1 = observe(data);
console.log(p1);
打印结果如图:
只打印了一次1,也就是说observe只执行了一次,从代码可以看出,将来执行get的时候,observe又会再次执行。什么意思呢?也就是说Vue3对于数据的深层监听只有当获取值的时候才会响应式处理,这样在性能上肯定会提升很多。争议
读到这里,抛开其他细节来讲,可能你会来句卧槽,那Vue2也可以在get的时候observe啊,确实如此,但是想一下是不是会有点问题呢?问题就在于每次执行get的时候,不管是获取哪个属性,都需要执行一下observe,并且它还是会向下遍历,这样增加了时间复杂度,可想而之,其性能是多么浪费的,还不如一次性深度监听到底呢?
而proxy则不一样,它只会响应式处理你get的那个层级,它不会深度遍历,这样解释你明白了吗?
总结
接下来总结一下二者响应式的差异
Object.defineProperty
深度监听,性能问题 新增删除属性问题,这个可以参考我前面写的一个文章总结一下Vue那些常用必会面试必考的API,这里说明了vue2为什么需要set&delete两个api 数组问题,需要重写数组原型的几个方法
Proxy
性能提升了一大截 解决了vue2的那些问题 兼容性有待处理
当然示例代码都没做优化,实际上源码肯定是对各种情况还做了处理,这里就不做介绍了,可以自己去看源码哈~如果你对本文有什么看法或者觉得不对的地方,请在评论区赐教!共勉进步~~
原文:juejin.cn/post/6933953813657157646
回复 资料包
领取我整理的进阶资料包回复 加群
,加入前端进阶群console.log("文章点赞===文章点在看===你我都快乐"
Bug离我更远了,快乐离我更近了