Vue响应式原理

100 阅读2分钟

数据劫持

vue2中采用的是Object.defineProperty方法,重写对象属性的gettersetter函数。vue3采用的是Proxy。

发布订阅者模式

对象的每个属性有一个Dep实例,专门存储依赖。

依赖收集:

某个组件在进行compile(指令解析、初始化视图时),因为js是单线程,所以当前只会有一个组件在compile。

  1. 这个组件会将自己赋值给全局变量target。

  2. 获取数据时,会触发该属性的getter函数,getter函数会将当前target添加到自己的dep中收集起来,完成依赖收集。

  3. 这个组件compile完成后,会释放target,target = null。

发布更新

数据变化时,发布通知,所有订阅者更新:

  1. 当我们修改一个数据时,会触发该属性的setter函数。

  2. setter函数中会调用dep中的notify方法,notify中会遍历所有依赖,调用他们的update方法,使所有的依赖(组件)去更新。

render函数和virtual DOM

从模板到真实DOM:

首先我们的template模板,会被vue-loader(compliler)编译成render()函数,render()函数返回的是virtual DOM,然后Vue基于virtual DOM生成真实DOM。

DOM更新过程:

生成virtual DOM的过程实质上是调用render()函数,而渲染函数和data的属性有依赖关系。渲染函数在调用过程中就会进行一个依赖收集,一旦这些数据发生变化,就会再次调用render()函数,生成新的virtual DOM。然后新旧virtual DOM会进行比较、区分,最终将少量的更改应用到真实DOM中。

virtual DOM

首先真实DOM属性值太多,操作起来是非常耗时的,而virtual DOM的节点实质是js对象,所以对比和操作都是在js层面完成的,速度会快很多。

{ tag: 'div', data: { attrs: {}, ...}, children:[] }
// virtual DOM节点,不难看出,结构很简单,主要就三个属性,标签、属性、子节点。

响应式原理图

image.png