Vue源码 流程讲解

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue源码 流程讲解相关的知识,希望对你有一定的参考价值。

模块分析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源码 流程讲解的主要内容,如果未能解决你的问题,请参考以下文章

Vue.js源码解析-Vue初始化流程

《Docker 源码分析》全球首发啦!

dhcp1.0源码分析,讲解dhcpd的源码流程。

Android 逆向ART 脱壳 ( DexClassLoader 脱壳 | DexClassLoader 构造函数 | 参考 Dalvik 的 DexClassLoader 类加载流程 )(代码片段

Android 逆向ART 脱壳 ( DexClassLoader 脱壳 | DexClassLoader 构造函数 | 参考 Dalvik 的 DexClassLoader 类加载流程 )(代码片段

Vue 源码解析 初始化流程