initState

首先在初始化_init里面调用initState进行初始化状态

initData

initData注入data,然后通过Obverse给data属性添加getter/setter

observe(value)

  • 给 value 对象定义的ob属性,记录当前的 observer 对象是否可响应式
  • 数组的响应式处理 主要是重写数组的几个特殊的方法 push/pop/sort/slice等,调用对应的notify,然后遍历数组中的成员,判断其类型决定是否调用observe
  • 对象的响应式处理,调用 walk 方法,遍历对象中的每个属性,调用defineReactive,给对象属性添加getter/setter

    defineReactive

    • 为每一个属性创建 dep 对象
      - 如果当前属性的值是对象,调用 observe
      - 定义 getter
      1. 收集依赖
      2. 返回属性的值
      - 定义 setter
      1. 保存新值
      2. 如果新值是对象,调用 observe
      3. 派发更新(发送通知),调用 dep.notify()

依赖收集过程

  • 分别initComputed和initWatch生成computed watcher和watch watcher

    watch watchers (initWatch)

    用户watcher收集依赖过程,用户watcher话,key是字符串,那么它的getter方法就是vue里面自定义的一个parsePath,这个方法内部就是从vm上读取数据,这个时候就会触发definePrototype里面的getter,把当前watcher Watcher push到dep.subs里面,这个时候就完成了用户watcher的依赖收益

    computed watchers (initComputed)

    computed watcher跟watcher watchers收集过程大部分是类似的。但是compute watchers是用一个_computedWatcher去储存的。而且在new Watch内部dirty为true,所以不会里面调用getter方法。
    那什么时候会收集computed watcher到dep.subs中呢。
    computed watcher在new Watcher完之后调用了defineComputed把getter重写了。
    如果当读取到这个computed 数据的时候,就会调用这个重写的getter方法。
    这个重写的getter内部就是通过Key从_computedWatcher上去找到刚刚缓存的watcher,然后调用watcher上面的evaluate方法,调用computed属性的function
    在调用computed function的时候,function里面的依赖就会把当前computed watcher添加到数据的dep.sub中。

    render watcher

  • 然后在$mount的时候生成渲染watcher.
    1. render watcher: 在 new Watcher的过程会调用this.getter方法,这个时候的this.getter是vm._update(vm._render).于是就会读取模板里面的指令和{{}}。这个时候就会触发Object.definePrototype的getter方法,把当前的渲染watcher push到当前数据的dep.subs中,完成了一次依赖收集。

每个watcher都会对应一个id,这个id是自增的,顺序是computed watcher, watch watcher,render watcher。那么在触发的时候也是按照这个顺序触发的。

依赖更新

  • 当用户有修改data的时候就会触发object.definePrototype的setter,setter里面就会取到当前数据对应的dep对象,然后通知dep.subs里面的watcher执行update。

  • update中调用queueWatcher()
  • queueWatcher() 是一个核心方法,去除重复操作,调用 flushSchedulerQueue() 刷新队列并执行 watcher
  • flushSchedulerQueue() 中对 watcher的过程会排序
  • 如果有 before,触发生命周期 的钩子函数 beforeUpdate,执行 watcher的过程会调用this.run(),它内部调用 this.get(),然后调用 this.cb() (渲染 watcher的 cb 是 noop)
  • 清空上一次的依赖
  • 触发 actived 钩子函数
  • 触发 updated 钩子函数

    Object.defineProerty VS proxy

    Object.defineProperty

  • 不能监听到数组length属性的变化;

  • 不能监听对象的添加;
  • 只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历。

Proxy

  • 可以监听数组length属性的变化;
  • 可以监听对象的添加;
  • 可代理整个对象,不需要对对象进行遍历,极大提高性能;
  • 多达13种的拦截远超Object.defineProperty只有get和set两种拦截。