Skip to content
大纲

响应式原理

vue2

首先需要了解三个概念和发布-订阅模式(data 属性发布者,setter 事务处理,watcher 订阅者)

  • Observer(数据的劫持者,用来劫持 data、props、computed 的数据)
  • Deps(依赖对象,每个对象属性都会有一个依赖对象,用来收集该属性的观察者)
  • Watcher(观察者,每个组件都会有一个,绑定的是组件更新)

具体流程

  1. 在组件实例初始化时,Observer 会使用 object.definePropty 对 data 这些对象遍历它的所有属性做 getter 和 setter 做数据劫持,同时也会创建一个观察者对象。
  2. 在 getter 里会将每个属性和一个依赖对象做关联
  3. 在首次渲染时,会去获取 data 里面的数据,触发这个属性的 getter 方法,然后 Deps 将这个观察者加入进其观察者列表里。
  4. 当属性修改,则触发了 setter 方法,依赖对象触发 notice 方法,遍历观察者列表触发更新,观察者接到依赖对象的通知,会触发其 update 方法,做组件级更新执行 render,diff 对比更新 vdom。
  5. 因为数组的长度是不定的,过长去遍历劫持是很耗性能的,所以针对数组,Observe 并不是使用和对象一样的方式劫持。
  6. 内部如果判断属性值是数组,会自定义 push,pop,shift,unshift,slice,sort,reverse 方法,方法内部会调用数组原型方法和触发依赖通知,然后使用 Object.defineProty 将其劫持,再将这个数组原型上的方法替换为自定义方法。
  7. 在首次渲染时,如果访问的时 data 里的数组时,会检查当前的观察者对象,然后将其加入到数组的 Deps 对象的列表里,当触发了自定义的数组方法,则会观察者会去执行更新。
  8. 因为 object.definePropty 只有 getter/setter,无法监听到对象属性的增删,数组也无法监听到项的修改和 length 的修改,所以提供了$set 方法去触发视图更新。

vue3

和 vue2 不同它需要先了解两个概念

  • reactive (内部做数据劫持)
  • effect (副作用函数,内部包含渲染方法)

具体流程

  1. 初始化实例时,会使用 reactive 将对象和集合使用 proxy,做 getter/setter/deletePropty 这些操作,针对对象和集合会有不同的处理方法。
  2. 然后会执行 effect 的方法,传入渲染方法,会在内部有执行逻辑,最后会把自身返回出去,作为实例的更新方法。
  3. effect 内部不仅会执行渲染方法,也会设置一些当前 effect 的属性和设置当前的活动 effect,以便在 getter 时做依赖收集
  4. 执行渲染方法,会去获取数据,触发 getter,使用 track 方法做依赖收集。
  5. track 方法内部,会根据当前的传入的对象,在实例 Map 集合查找有没有以改对象为 key 的属性,没就创建一个 Set 集合。然后在这个 Set 集合里查找有没有传入 key 的 effect,没就将当前活动的 effect 加入到该 Set 里。
  6. 当修改数据值,触发 setter,使用 trigger 方法做更新,trigger 内部首先会查找当前对象里有没有这个属性,有就查找 Map 集合里的 Set 集合里的 effect 方法,然后执行。没有就执行新增方法,做依赖的收集。
  7. 渲染方法里会 patch,diff 这些,最后渲染页面

Released under the MIT License.