浅谈vue响应式原理

本文详细解析了Vue中响应式系统的实现原理,重点在于数据的Object.defineProperty劫持和依赖收集。依赖收集发生在getter阶段,因为每个数据属性对应一个独立的Dep依赖收集器,收集与其相关的Watcher。在数据变化时,只通知对应的Watcher,确保组件的高效更新。文章还探讨了为何不能在Watcher创建后任意位置收集依赖,以及数据与Watcher的一对多依赖关系。
摘要由CSDN通过智能技术生成

VUE使用Object.defineProperty特性劫持传递进来的data对象,把所有property 的getter/setter重写。在getter阶段将依赖者(Watcher)收集起来,在数据变化的setter阶段通知所有Watcher,以此来实现当数据更新组件将自动渲染的“响应式”原理。

在学习Vue响应式原理时,依赖追踪(依赖收集)不算太好理解,会面对“究竟谁依赖谁?谁是依赖者?谁是被依赖者?依赖者在什么地方收集,如何收集?”等一连串问题。

 谁是依赖者?谁是被依赖者?

根据官方原理图看对象之间的关系,显然观察者(Watcher)是依赖者,data是被依赖者。Watcher需要被收集起来,当data变化的时候告知Watcher做某些事情,每个组件会对应有一个Watcher,它的作用是保存当依赖关系发生变化时动态执行的函数,比如组件的重新渲染。


学习原理最好的方式还是在浏览器打断点跟踪推栈查看源码最好。当然事先要知道一些概念,如何依赖追踪,观察者的设计模式,什么虚拟DOM等,不然直接看源码会头晕脑胀的。

数据如何被监听劫持

右侧推栈可以看到数据初始化到数据被劫持监听的过程。Observer实例运行的walk方法调用defineReactive$$1做到数据监听。注意的是在数据初始化阶段,依赖并没有收集。

 

 
Watcher创建


1.在组件实例生命周期的挂载阶段。可以看到Watcher被创建。
2.从2图看运行了一个赋值语句,将watcher赋值给Dep.target一个全局变量,这是为了在依赖收集阶段做的准备。

 图1


图2


依赖在哪里收集,如何收集


1.依赖收集在组件渲染阶段,当组件需要用到(touch)数据时,通过获取前面数据监听定义的值在getter阶段收集依赖。
2.dep是一个依赖收集器,将依赖收集起来,然后在数据变化时通知每个watcher。

 

疑问点,为什么在getter阶段运行dep.depend(),而不是在创建完watcher后可以在任意地方运行将此收集起来,然后等到数据发生变化时通知wathcer。

如果可以在任意地方收集,则dep的subs成员需要是全局对象,这样当某个数据变化后将会通知所有的watcher,这是不合理的。正确的做法是每个数据属性都有对应得一个Dep依赖收集器,收集相关的watcher。因此只能在getter阶段运行dep.depend(),从设计逻辑上订阅(touch)某个数据的时候才开始收集依赖才是合理的。那么能不能在watcher创建给 Dep.target赋值后,使用obj.defindProperty劫持对象属性呢?显然也是不现实的,当其它Watcher依赖当前data属性时也需要重新重写getter/setter,这会覆盖原来的dep。Data和watcher之间的关系是一对多的依赖关系,而不是一对一。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值