简述 Vue 响应式处理过程

216 阅读2分钟

image.png

  1. Vue 的响应式是从 Vue 的实例 init() 方法中开始的,在 init() 方法中先调用 initState() 初始化 Vue 实例的状态,在 initState 方法中调用了 initData() , initData() 是把 data 属性注入到 Vue 实例上,并且调用 observe(data) 将 data 对象转化成响应式的对象。

  2. observe 是响应式的入口, 在 observe(value) 中,首先判断传入的参数 value 是否是对象,如果不是对象直接返回。再判断 value 对象是否有 _ob_ 这个属性,如果有说明做过了响应式处理,则直接返回,如果没有,创建 observer 对象,并且返回 observer 对象。

  3. 在创建 observer 对象时,给当前的value对象定义不可枚举的 _ob_ 属性,记录当前的 observer 对象,然后再进行数组的响应式处理和对象的响应式处理,数组的响应式处理就是拦截数组的几个特殊的方法,push 、pop 、 shift 等,然后找到数组对象中的__ob__对象中的dep,调用 dep 的 notify() 方法,再遍历数组中每一个成员,对每个成员调用 observer() ,如果这个成员是对象的话,也会转换成响应式对象。对象的响应式处理,就是调用 walk 方法,walk 方法就是遍历对象的每一个属性,对每个属性调用 defineReactive 方法

  4. defineReactive 会为每一个属性创建对应的 dep 对象,让 dep 去收集依赖,如果当前属性的值是对象,会调用 observe 。 defineReactive 中最核心的方法是 getter 和 setter。 getter 的作用是收集依赖,收集依赖时, 为每一个属性收集依赖,如果这个属性的值是对象,那也要为子对象收集依赖,最后返回属性的值。在 setter 中,先保存新值,如果新值是对象,也要调用 observe ,把新设置的对象也转换成响应式的对象,然后派发更新(发送通知),调用 dep.notify()

  5. 收集依赖时,在 watcher 对象的 get 方法中调用 pushTarget ,记录 Dep.target 属性,访问 data 中的成员的时候收集依赖,defineReactive 的 getter 中收集依赖,把属性对应的 watcher 对象添加到 dep 的 subs 数组中,给 childOb 收集依赖,目的是子对象添加和删除成员时发送通知。

  6. 在数据发生变化的时候,会调用 dep.notify() 发送通知,dep.notify() 会调用 watcher 对象的 update() 方法,update() 中的调用的 queueWatcher() 会去判断 watcher 是否被处理,如果这个 watcher 对象没有的话添加到 queue 队列中,并调用 flushScheduleQueue() ,flushScheduleQueue() 触发 beforeUpdate 钩子函数调用 watcher.run():run()-->get() --> getter() --> updateComponent()

  7. 然后清空上一次的依赖

  8. 触发 actived 的钩子函数

  9. 触发 updated 钩子函数