vue2源码–依赖收集
Dep
Dep是用来收集渲染的变量的。比如 {{age}} {{text}} 需要渲染,但是在后续中改变了age, text, 以及hobby这个变量,只会收集需要渲染的数据。
Watcher
通知dep的变化,被dep收集
一个dep可以有多个watcher 一个属性可以在多个组件中使用
一个watcher也可以有多个dep 一个组件可以使用多个属性
Observer 将数据定义为响应式,每个 Observer 实例都有自己的 Dep 来管理依赖。实例化 Wacther 的时候进行求值会触发 getter ,进而执行 dep.depend() 将当前 Wacther 加入 Dep 维护的依赖列表,这就是依赖收集过程。
数据发生变化触发 setter 执行 dep.notify,Dep 会执行所有依赖的 update 方法并加入异步更新队列,这就是触发依赖过程。
渲染的原理
- 将render函数传入watcher
- render函数执行get()函数
- 渲染数据,每个数据都有dep,只有被渲染的才会有dep.id
- 依次渲染数据,渲染完毕,将dep.target设置为null
- 如有变更,会重新执行渲染函数,即重新watcher。
dep.js
let id = 0
class Dep {
constructor() {
this.id = id++
this.subs = []
}
addSub(watcher) {
console.log(7)
console.log("{addSub dep}")// 记录watcher
this.subs.push(watcher)
}
depend() {
// this.subs.push(Dep.target)
console.log("{depend}")
Dep.target.addDep(this)
}
notify() {
console.log('{notify}')
this.subs.forEach(watcher => watcher.update())
}
}
Dep.target = null
export default Dep
watcher.js
import Dep from './dep'
let id = 0
class Watcher {
constructor(vm, exprOrFn, options) { //vm是实例, exprOrFn是render函数。
this.id = id++
this.renderWatcher = options // off
this.getter = exprOrFn // 调用这个函数,可以发生取值操作
this.deps = [] // 计算属性和清理工作
this.depsId = new Set() // 去重
this.get()
}
addDep(dep) {
console.log(5)
console.log(dep)
console.log("[addDep watcher]")
let id = dep.id
if (!this.depsId.has(id)) {
console.log(6)
this.deps.push(dep)
this.depsId.add(id)
dep.addSub(this)
}
}
get() {
console.log("[get]")
Dep.target = this
console.log(1)
this.getter()
Dep.target = null
}
update() {
console.log("[update]")
this.get()
}
}
export default Watcher
observe/index.js
import {newArrayProto} from "./array";
import Dep from "./dep";
class Observer {
constructor(data) {
// data.__ob__ = this
this.dep = new Dep()
Object.defineProperty(data, '__ob__', {
value:this,
enumerable:false
})
if (Array.isArray(data)) {
data.__proto__ = newArrayProto
} else{
this.walk(data)
}
}
walk(data) {
Object.keys(data).forEach(key => {
// debugger
definedReactive(data,key,data[key])
})
}
observeArray(data) {
data.forEach(item => observe(item))
}
}
export function definedReactive(target, key, value) {
observe(value)
let dep = new Dep()
Object.defineProperty(target, key, {
get() {
if (Dep.target) {
console.log(4)
console.log("value", value)
dep.depend()
}
return value
},
set(newValue) {
if(value === newValue) return
observe(newValue)
value = newValue
dep.notify()
}
})
}
export function observe(data) {
if (typeof data !== 'object' || data == null) {
return
}
if (data.__ob__ instanceof Observer) {
return data.__ob__
}
return new Observer(data)
}
上面代码中的console.log(1)等等可以帮助理解代码逻辑