首页 > 其他 > 详细

Vue源码 流程讲解

时间:2021-05-16 00:21:51      阅读:16      评论:0      收藏:0      [点我收藏+]

模块分析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)的依赖中

备用小知识

  • initWatch内部使用了vm.$watch(expOrFn, handler, options)方法
  • 初始化流程initData,initComputed,initWatch,parseHtml,new Wacther : get=> (_update(_render)),
  • _render产生vnode
  • _update调用patch
  • watcher get调用
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
  };
  • _update(_render)是render&&update的getter,在getter调用中,Dep.target=watcher

Vue源码 流程讲解

原文:https://www.cnblogs.com/x-mao/p/14772474.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!