【手把手教你搓Vue响应式原理】(五) Watcher 与 Dep

如题所述

第1个回答  2022-06-25

【手把手教你搓Vue响应式原理】(一)初识Vue响应式

【手把手教你搓Vue响应式原理】(二)深度监测对象全部属性

【手把手教你搓Vue响应式原理】(三)observe 以及 ob

【手把手教你搓Vue响应式原理】(四) 数组的响应式处理

之前已经将数据劫持已经全部完成了。

那么,接下来,主要的要点就是在于两点,依赖收集和触发依赖更新。

它的意义主要在于控制哪些地方使用了这个变量,然后,按照最小的开销来更新视图

首先,要先明白,依赖是什么,比方说在我们的模板中有 {{a}} ,那么,这个地方就有对于变量 a 的依赖。

在模板编译的时候,就会触发 a 变量的 getter 。

然后,当我们执行 a++; 的时候,那么,我们就要触发依赖的更新,当初模板中 {{a}} 的地方,就要更新,是吧!

所以,我们都是 在 getter 中收集依赖,在 setter 中触发依赖更新

这一节的内容,主要就是用来专门讲清楚这两件事情。

依赖收集和触发依赖更新主要由两个类来完成, Dep 和 Watcher 。

Dep 和 Watcher 在设计模式中,就是 发布-订阅者 的模式。

而依赖,你可以理解为所谓的订阅者。

Dep 说白了就是发布者,它的工作就是依赖管理,要知道哪些地方用到了这个变量,可能用到这个变量的地方有很多,所以,它会有多个订阅者。

然后,每个变量都应该有属于自己的 Dep ,因为每个变量所在的依赖位置是不一样的,所以他们的订阅者也不一样。

然后在变量更新之后,就去通知所有的订阅者(Watcher),我的变量更新了,你们该触发视图更新了。

Watcher 说白了就是订阅者,它接受 Dep 发过来的更新通知之后,就去执行视图更新了。

它其实就是所谓的 watch 监听器,变量改变之后,执行一个回调函数。

我们先按照图例来创建我们的 Dep 类

根据我们的需求:

Dep 我们在前面也说了,每个属性都应该有它自己的 Dep ,用来管理依赖。

所以,首先,如果我们在 Observer 中创建 Dep,那不就可以了。毕竟 Observer 会遍历到每一个对象。

所以,很明显,我们可以在 defineReactive 的 get 中收集依赖

因为有了 if(Dep.target) 的判断,所以, 只有绑定 Watcher 的变量触发 getter 时,才会添加依赖

这个 Dep.target 其实就是 Watcher 的实例

所以,很明显,我们可以在 defineReactive 的 set 中收调用 notify() 方法告知 Watcher 实例,数据更新了。

至此, Dep 的所有职责,我们已经帮它完成了。

其实照道理应该有一个删除依赖,我们这里就不再扩展了。

首先, Watcher 实例应该大家会相对而言更加好理解点,因为,我们有一个 watch 侦听器,大家一定都很熟悉,这两个其实一样。

我们先按照图例来创建我们的 Watcher 类

根据我们的需求:

这个 parsePath 需要单独拎出来说一下,比方说我们现在有这么一个对象

我们要监听到 a.b.c.d ,所以,我们需要下面的这种格式

所以,这个 get 很明显就有点难度了。 我们需要通过循环 拿到 a.b 然后 .c 然后 .d。

我们将这个方法命名为 parsePath 。

入参接受我们的 b.c.d ,我们可以看到 第一句执行之后 segments=['b','c','d'] ,然后进行第二层,这是返回了一个方法,按照循环,那就是 obj=obj.b => obj=obj.c => obj=obj.d ,所以,就是返回一个对象的 obj.b.c.d,相当于是遍历字符串中的属性树。

在执行 a.b.c.d=55; 的同时,我们的控制台就会输出 ok 55 10 。

【尚硅谷】Vue源码解析之数据响应式原理

相似回答
大家正在搜