You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Watcher构造函数(核心): 实例化 watcher 对象, 接受 dep 通知, 触发回调逻辑
classWatcher{vm: Component;expression: string;cb: Function;id: number;deep: boolean;user: boolean;lazy: boolean;sync: boolean;dirty: boolean;active: boolean;deps: Array<Dep>;newDeps: Array<Dep>;depIds: ISet;newDepIds: ISet;getter: Function;value: any;constructor(vm: Component,expOrFn: string|Function,cb: Function,options?: Object){this.vm=vm/*_watchers存放订阅者实例*/vm._watchers.push(this)// optionsif(options){this.deep=!!options.deepthis.user=!!options.userthis.lazy=!!options.lazythis.sync=!!options.sync}else{this.deep=this.user=this.lazy=this.sync=false}this.cb=cbthis.id=++uid// uid for batchingthis.active=truethis.dirty=this.lazy// for lazy watchersthis.deps=[]this.newDeps=[]this.depIds=newSet()this.newDepIds=newSet()this.expression=process.env.NODE_ENV!=='production'
? expOrFn.toString()
: ''// parse expression for getter/*把表达式expOrFn解析成getter*/if(typeofexpOrFn==='function'){this.getter=expOrFn}else{this.getter=parsePath(expOrFn)if(!this.getter){this.getter=function(){}process.env.NODE_ENV!=='production'&&warn(`Failed watching path: "${expOrFn}" `+'Watcher only accepts simple dot-delimited paths. '+'For full control, use a function instead.',vm)}}this.value=this.lazy
? undefined
: this.get()}/*获得getter的值并且重新进行依赖收集*/get(){/*将自身watcher观察者实例设置给Dep.target,用以依赖收集。*/pushTarget(this)letvalueconstvm=this.vm/* 执行了getter操作,看似执行了渲染操作,其实是执行了依赖收集。 在将Dep.target设置为自身观察者实例以后,执行getter操作。 譬如说现在的的data中可能有a、b、c三个数据,getter渲染需要依赖a跟c, 那么在执行getter的时候就会触发a跟c两个数据的getter函数, 在getter函数中即可判断Dep.target是否存在然后完成依赖收集, 将该观察者对象放入闭包中的Dep的subs中去。 */if(this.user){try{value=this.getter.call(vm,vm)}catch(e){handleError(e,vm,`getter for watcher "${this.expression}"`)}}else{value=this.getter.call(vm,vm)}/*如果存在deep,则触发每个深层对象的依赖,追踪其变化*/if(this.deep){/*递归每一个对象或者数组,触发它们的getter,使得对象或数组的每一个成员都被依赖收集,形成一个“深(deep)”依赖关系*/traverse(value)}/*将观察者实例从target栈中取出并设置给Dep.target*/popTarget()this.cleanupDeps()returnvalue}/*添加一个依赖关系到Deps集合中*/addDep(dep: Dep){constid=dep.idif(!this.newDepIds.has(id)){this.newDepIds.add(id)this.newDeps.push(dep)if(!this.depIds.has(id)){dep.addSub(this)}}}/*清理依赖收集*/// 每次数据变化都会重新 render, 那么 vm._render() 方法又会再次执行,并再次触发数据的 getters,// 所以 Wathcer 在构造函数中会初始化 2 个 Dep 实例数组,newDeps 表示新添加的 Dep 实例数组,而 // deps 表示上一次添加的 Dep 实例数组。// cleanupDeps 函数会首先遍历 deps,移除对 dep.subs 数组中 Wathcer 的订阅,// 然后把 newDepIds 和 depIds 交换,newDeps 和 deps 交换,并把 newDepIds 和 newDeps 清空。cleanupDeps(){/*移除所有观察者对象*/leti=this.deps.lengthwhile(i--){constdep=this.deps[i]if(!this.newDepIds.has(dep.id)){dep.removeSub(this)}}lettmp=this.depIdsthis.depIds=this.newDepIdsthis.newDepIds=tmpthis.newDepIds.clear()tmp=this.depsthis.deps=this.newDepsthis.newDeps=tmpthis.newDeps.length=0}/* 当依赖发生改变的时候进行回调。 */update(){/* istanbul ignore else */if(this.lazy){this.dirty=true}elseif(this.sync){/*同步则执行run直接渲染视图*/this.run()}else{/*异步推送到观察者队列中,由调度者调用。*/queueWatcher(this)}}/* 调度者工作接口,将被调度者回调。 */run(){if(this.active){constvalue=this.get()if(value!==this.value||// Deep watchers and watchers on Object/Arrays should fire even// when the value is the same, because the value may// have mutated./* 即便值相同,拥有Deep属性的观察者以及在对象/数组上的观察者应该被触发更新,因为它们的值可能发生改变。 */isObject(value)||this.deep){// set new valueconstoldValue=this.value/*设置新的值*/this.value=value/*触发回调渲染视图*/if(this.user){try{this.cb.call(this.vm,value,oldValue)}catch(e){handleError(e,this.vm,`callback for watcher "${this.expression}"`)}}else{this.cb.call(this.vm,value,oldValue)}}}}/** * Evaluate the value of the watcher. * This only gets called for lazy watchers. *//*获取观察者的值*/evaluate(){this.value=this.get()this.dirty=false}/*收集该watcher的所有deps依赖*/depend(){leti=this.deps.lengthwhile(i--){this.deps[i].depend()}}/*将自身从所有依赖收集订阅列表删除*/teardown(){if(this.active){/*从vm实例的观察者列表中将自身移除,由于该操作比较耗费资源,所以如果vm实例正在被销毁则跳过该步骤。*/if(!this.vm._isBeingDestroyed){remove(this.vm._watchers,this)}leti=this.deps.lengthwhile(i--){this.deps[i].removeSub(this)}this.active=false}}}
Watcher 又干嘛了呢
// 首先我们要实例化嘛, new Watcher()会调用自身的 getter, 结果是添加一个Dep targetexportfunctionpushTarget(_target: ?Watcher){if(Dep.target)targetStack.push(Dep.target)Dep.target=_target}pushTarget(this);// 其实是添加了依赖// 还有就是等待 dep 通知我, 然后出发相应的回调逻辑
The text was updated successfully, but these errors were encountered:
数据响应式原理梳理
数据响应式: 与data绑定的视图, 互相状态的更改是双向的
这里以 data 的初始化来梳理 vue 是如何将数据变为响应式的...
原理图
初始化 data
进行数据观测 Observer: 返回一个 ob 实例对象
Observer为数据加上响应式属性进行双向绑定。如果是对象则进行深度遍历,为每一个子对象都绑定上方法,如果是数组则为每一个成员都绑定上方法。
结果
: 添加__ob__属性; 调用defineReactive方法实现响应式defineReactive核心方法: 添加响应式
我们看到添加响应式的时候引入了一个dep对象,
并在get(属性访问时)调用 dep.depend(),
在set(属性设置时)调用 dep.notify();
Dep 构造函数: 实例化一个 dep 对象, 管理 watcher
Watcher构造函数(核心): 实例化 watcher 对象, 接受 dep 通知, 触发回调逻辑
The text was updated successfully, but these errors were encountered: