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}")// 记录watcherthis.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 // offthis.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.idif (!this.depsId.has(id)) {console.log(6)this.deps.push(dep)this.depsId.add(id)dep.addSub(this)}}get() {console.log("[get]")Dep.target = thisconsole.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__ = thisthis.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 => {// debuggerdefinedReactive(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) returnobserve(newValue)value = newValuedep.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)等等可以帮助理解代码逻辑