概述
首先要知道vue2 是2013年 基于 ES5开发出来的
我们常说的重渲染就是重新运行render函数
vue2响应式原理简单来说就是vue官网上的这图片
通过 Object.defineProperty 遍历对象的每一个属性,把每一个属性变成一个 getter 和 setter 函数,读取属性的时候调用 getter,给属性赋值的时候就会调用 setter.
当运行 render 函数的时候,发现用到了响应式数据,这时候就会运行 getter 函数,然后 watcher(发布订阅)就会记录下来。当响应式数据发生变化的时候,就会调用 setter 函数,watcher 就会再记录下来这次的变化,然后通知 render 函数,数据发生了变化,然后就会重新运行 render 函数,重新生成虚拟 dom 树。
深入了解:
我们要明白,响应式的最终目标:是当对象本身或对象属性发生变化时,会运行一些函数,最常见的就是 render 函数。不是只有 render,只要数据发生了变化后运行了一些函数,就是响应式,比如 watch。
在具体实现上,vue 采用了几个核心部件:
1.Observer
2.Dep
3.Watcher
4.Scheduler
Observer
observer 要实现的目标非常简单,就是把一个普通的对象转换成响应式的对象
为了实现这一点,observer 把对象的每个属性通过 object.defineProperty 转换为带有 getter 和 setter 的属性,这样一来,当访问或者设置属性时,vue 就会有机会做一些别的事情。
在组件的生命周期中,这件事发生在 beforeCreate 之后,create 之前。
具体实现上,他会递归遍历对象的所有属性,以完成深度的属性转换。
但是由于遍历只能遍历到对象的当前属性,无法监测到将来动态添加或者删除的属性,因此 vue 提供了$set和$delete 两个实例方法,但是 vue 并不提倡这样使用,我讲到 dep 的时候我再说为什么。
对于数组的话,vue 会更改它的隐式原型,之所以这样做是因为 vue 需要监听那些可能改变数组内容的方法。
数组 --> vue 自定义的对象 --> Array.prototype
总之,observer 的目标,就是要让一个对象,它属性的读取,赋值,内部数组的变化都要能够被 vue 感知到。
Dep
这里有两个问题没解决,就是读取属性时要做什么事,属性变化时又要做什么事,这个问题就得需要 dep 来解决
dep 的含义是 dependency 表示依赖的意思。
vue 会为响应式对象中的每一个属性,对象本身,数组本身创建一个 dep 实例,每个 dep 实例都可以做两件事情:
1,记录依赖:是谁在用我
2,派发更新:我变了,我要通知那些用我的人
当读取响应式对象的某一个属性时,他会进行依赖收集,有人用到了我
当改变某个属性时,他会派发更新,那些用我的人听好了,我变了
为什么尽量不要使用$set $delete ?
因为如果模板上没有用到值的话,你凭空加了一个数据,理论上来说应该不会重新运行render函数,但是上一级的dep发现自身发生改变了,所以也会导致重新运行render函数。
所以vue不建议使用$set 和$delete,最好提前先写上数据,哪怕先给数据赋值为 null;
watcher
这里又出现了一个问题,就是 dep 如何知道是谁在用我呢
watcher 就解决了这个问题
当函数执行的过程中,用到了响应式数据,响应式数据是无法知道是谁在用自己的
所以,我们不要直接执行函数,而是把函数交给一个 watcher 的东西去执行,watch 是一个对象,每个函数执行时都应该创建一个 watcher,通过 wacher 去执行
watcher 会创建一个全局变量,让全局变量记录当前负责执行的 watcher 等于自己,然后再去执行函数,在函数执行的过程中,如果发生了依赖记录,那么 dep 就会把这个全局变量记录下来,表示有一个 wathcer 用到了我这个属性。
当 dep 进行派发更行时,他会通知之前记录的所有 watcher,我变了。
Scheduler
现在还剩下最后一个问题啊,就是 dep 通知 watcher 之后,如果 wathcer 执行重新运行对应的函数,就有可能导致频繁运行,从而导致效率低下,试想,如果一个交给 watcher 的函数,它里面用到了属性 a,b,c,d,那么 a,b,c,d 都会记录依赖,然后这四个值都以此重新赋值,那么就会触发四次更新,这样显然不行啊,所以当 watcher 收到派发更新的通知后,实际上并不是立即执行,而是通过一个叫做 nextTick 的工具方法,把这些需要执行的 watcher 放到事件循环的微队列,nextTick 是通过 Promise then 来完成的。
也就是说,在响应式数据发生变化时,render 函数执行是异步的,并且在微队列中。
最后
以上就是腼腆诺言为你收集整理的vue2响应式原理的全部内容,希望文章能够帮你解决vue2响应式原理所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复