模块分析Vue源码,源码版本2.6.9
场景1:初始化vue实例,渲染到页面,点击handleChangeWeight方法
{
data(){
return {
weight:120
}
},
watch:{
weight(){
console.log(‘change!!!‘)
}
},
computed:{
type(){
return this.weight > 150 ? ‘胖‘ : ‘瘦‘
}
},
methods:{
handleChangeWeight(){
this.weight = 200
}
}
}
1, data初始化,weight设置为响应式时,有一个dep保存依赖,在其他变量获取当前weigth时,收集其他变量的Watcher
// 每一个变量都会运行defineReactive
// 一下代码位置src\core\observer\index.js
// 代码有删减
function defineReactive(obj,key,val){
const dep = new Dep() // 依赖
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
const value = val
if (Dep.target) {
dep.depend() // 收集依赖
}
return value
},
set: function reactiveSetter (newVal) {
const value = getter ? getter.call(obj) : val
val = newVal
dep.notify() // 设置值的时候通知其他
}
})
}
2,computed初始化,创建watcher,watcher的lazy是true在最后再执行
var watchers = vm._computedWatchers = Object.create(null);
watchers[‘type‘] = new Watcher(
vm,
getter || noop,
noop,
computedWatcherOptions:{lazy:true}
)
Object.defineProperty(vm, ‘type‘, {
set:noop,
get:() => {
return computedGetter () {
var watcher = vm._computedWatchers && vm._computedWatchers[key];
if (watcher) {
if (watcher.dirty) {
watcher.evaluate();
}
if (Dep.target) {
// 把computed:type的watcher添加为_update(_render)的依赖
// 在render&&update的getter中调用这个方法,Dep.target=render&&update的watcher
watcher.depend()
}
return watcher.value
}
}
}
})
3,初始化watch
watcher = new Wacther(vm,‘weight‘,watch:{weight(){}})
lazy:false 执行geter,获取weight的数值,get方法,收集weight->watcher
watcher = {
cb(){} === weight->watcher,
expression:‘weight‘,
get:_=> 处理深度监听‘例如panda.name‘,触发weight的get,返回weight的value,
user:true,
value:120
}
4, 在解析完html,转vnode时,调用computed:type的getter方法,调用weight的get方法,收集依赖
_s(type)
5,把computed:type的watcher添加为_update(_render)的依赖
6, 点击change
触发weight的setter,触发依赖watcher.update,
watchers开启一个队列,保存非lazy的watcher,并Promise.resolve().then(flushCallbacks)
函数处理完成
7,调用微服务
调用微任务,flushCallbacks
排序watchers,依次调用watcher.run
watch,update(render),addComputed to update(render)的依赖中
备用小知识
Watcher.prototype.get = function get () {
pushTarget(this); // push
var value;
var vm = this.vm;
try {
value = this.getter.call(vm, vm);
} catch (e) {
if (this.user) {
handleError(e, vm, ("getter for watcher \"" + (this.expression) + "\""));
} else {
throw e
}
} finally {
if (this.deep) {
traverse(value);
}
popTarget(); // pop
this.cleanupDeps(); // 清空
}
return value
};
原文:https://www.cnblogs.com/x-mao/p/14772474.html