开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情
Dep类,依赖管理
作用概述
Dep类主要有两个作用,即:
- 依赖收集
depend() - 派发更新依赖
通知Watcher,notify()
以上可以统称为依赖的收集和通知更新,Dep 可以理解为对依赖的一种管理
Dep与Watcher的关联性: Dep收集Watcher需要的依赖在哪使用、对应的使用场景等。
源码分析
现在我们可以看一下Dep的源码
let uid = 0; //作为一个唯一的索引
class Dep {
constructor() {
this.id = uid++;
this.subs = []
}
// 依赖收集
depend() {//向订阅者数组里添加订阅者
if(Dep.target) {
// Dep.target是当前的watcher,将当前的依赖推到subs中
this.subs.push(Dep.target)
}
}
// 派发更新
notify() {//通知更新
const subs = this.subs.slice();
for (var i = 0, l = subs.length; i < l; i++) {
// 遍历dep中的依赖,对每个依赖执行更新操作
subs[i].update();
}
}
}
Dep.target = null;
收集依赖
那我们是如何收集依赖呢? 我们可以定义一个全局的Dep.watcher来监控他的内部有哪些属性是正在读取数据的,我们通过收集依赖把它放到我们的添加订阅数组(subs:存放Watcher的实例,这里可以将subs看作存放watcher的数组)中。
还记得我们的数据拦截吗defineReactive函数,每一个我们实例化为Observe的数据都拥有一个getter和setter,而一开始即实例化一个Dep实例,这里的getter是一个重写的getter(setter也一样),在重写的getter方法中会进行依赖的收集,也就是调用dep.depend的方法。在setter阶段,比较两个数不同后,会调用依赖的派发更新。即dep.notify
getter --> dep.depend依赖管理,通过依赖收集拿到我需要的watcher
setter --> dep.notify提醒更新
派发更新
那么Watcher是如何实现派发更新的呢? 派发更新分为两部分,更新依赖和创建依赖
更新依赖:可以理解为原来的数据被重写
创建依赖:new一个新数据(一个新的watcher)
派发更新update函数会先查看该传入数据的类型是不是对象(即需不需要重新收集依赖)
Watcher类,依赖收集
作用概述
watcher有一个主要的功能,即创建依赖。那么你可能会问——创建依赖和收集依赖我区别不开啊?没关系,这里我将针对依赖收集和创建依赖进行解析
首先,我必须说明什么是依赖,本人对依赖的理解为:每一个Watcher实例就是一个依赖。
创建依赖是什么:指数据在哪需要被使用就需要一个依赖。依赖收集发生在Object.defineProperty()的getter中。
依赖收集是什么:订阅数据变化的 Watcher 收集的过程(具体收集过程为,将dep.target推入栈,变成一个又一个watcher实例),这里需要和之前说过的依赖收集联系起来。
Observe类
以上两个类其实都包含在Observe中,observe作为观察者类,对象只要是设有__ob__属性,即可在她身上找到getter、setter并可以成功调用,换句话说也就是拥有这样的属性的数据即可实现依赖收集与派发。
graph TD
Observe类 --> getter
Observe类 --> setter
getter --> 调用dep.depend
setter --> 调用dep.notify
总结
本节主要是针对之前对于派发依赖、依赖收集以及创建依赖三者关系的不清晰以及Watcher、Dep、Observe三者之间的关系进行了。