请简述 Vue 响应式原理

676 阅读2分钟

一、入口 initState()

  • 位置 src/core/instance/state.js
  • 响应式从init开始、init调用initState()初始话状态,initState中调用initData(),将data的属性,注入到vue实例,调用observe()将其转换成添加get, set方法转换响应式对象
export function initState (vm: Component) {
  vm._watchers = []
  ...
  if (opts.data) {
    initData(vm)
  } else {
    observe(vm._data = {}, true /* asRootData */)
  } 
  ...
}
function initData (vm: Component) {
  let data = vm.$options.data
  ...
  // 响应式处理
  observe(data, true /* asRootData */)
}

二、observe(value)

  • 位置 src/core/observer/index.js
  • 判断如果不是对象,或者是虚拟节点, 直接返回
  • 如果value含有__ob__属性, 且是Observe类型, 则已经做响应式处理过, 返回ob, 如果没有处理过, 则创建new Observer(value)

三、Observer

  • 位置 src/core/observer/index.js
  • 为value对象定义不可枚举的__ob__属性, 记录当前的observer对象
  • 如果value是数组
    • 为value的原型上添加自定义的数组方法
    • 调用this.observeArray(value)
    • 遍历数组中的为数组中的每一个对象创建一个 observer 实例
  • 如果对象不是数组,调用walk(value),遍历对象中的每一个属性,调用defineReactive(obj, keys[i]),转换成 setter/getter

四、defineReactive

  • 位置vue/src/core/observer/index.js
  • 为每一个属性创建dep对象, 如果当前属性值是对象, 递归调用observe(), getter为每一个属性收集依赖, 如果属性值是对象, 也需要为对象的每一个属性创建属性依赖, 最终返回属性值, setter设置新值, 如果新值是对象, 则调用observe,然后派发更新(发送通知),调用dep.notify()

五、收集依赖

  • 在Watcher的构造器中获取this.value = this.lazy? undefined: this.get(),调用get(), get方法中调用pushTarget(this),标记Dep.target属性(Dep.target = target
  • 在访问data中的成员时候收集依赖, defineReactive的getter收集依赖
  • 把属性对应的watcher对象添加到dep的subs数组中
  • 给childOb收集依赖, 目的是子对象添加和删除成员时发送通知

六、Watcher

  • 触发beforeUpdate钩子函数
  • 当属性的值发生变化时, 会调用dep.notify(), 会遍历subs的Watcher对象,调用update方法
  • 调用watcher.run()-->this.getter()(这个getter是this.getter = parsePath(expOrFn)也就是创建watcher时的第二个参数updateComponent)-->调用updateComponent()
  • 清空上一次的依赖
  • 触发actived钩子函数
  • 触发updated钩子函数