一文搞定数据响应式原理
关注公众号“执鸢者”,回复“资料”获取 500G 资料(各“兵种”均有),还有专业交流群等你一起来潇洒。(哈哈)
在 Vue 中,其中最最最核心的一个知识点就是数据响应式原理,数据响应式原理归结起来就包含两大部分:侦测数据变化、依赖收集,了解这两个知识点就了解到了数据响应式原理的精华。
一、侦测数据变化
能够帧听到数据变化是数据响应式原理的前提,因为数据响应式正是基于监听到数据变化后来触发一系列的更新操作。本次介绍数据响应式原理将基于 Vue2.x 进行,其将数据变为可被侦测数据时主要采用了 Object.defineProperty()。
1.1 非数组对象
下面先举一个非数组对象的例子
观察上面的对象,可以发现其是存在包含关系的(即一个对象中可能包含另一个对象),那么自然会想到通过递归的方式实现,在 Vue 中为了保证代码较高的可读性,引入了三个模块实现该逻辑:observe、Observer、defineReactive,其调用关系如下所示:
1.1.1 observe
这个函数时帧听数据变化的入口文件,通过调用该函数一方面触发了其帧听对象数据变化的能力;另一方面定义了何时递归到最内层的终止条件。
1.1.2 Observer
这个函数的目的主要有两个:一个是将该实例挂载到该对象 value 的__ob__属性上(observe 上用到了该属性,通过判断是否有该属性判断是否已经属于帧听状态);另一个是遍历该对象上的所有属性,然后将该属性均变为可帧听的(通过调用 defineReactive 实现)。
1.1.3 defineReactive
这个方法主要是将 Object.defineProperty 封装到一个函数中,做这一步操作的原因是因为 Object.defineProperty 设置 set 属性时需要一个临时变量来存储变化前的值,通过封装利用闭包的思想引入 val,这样就不需要在函数外面再设置临时变量了。
1.2 数组
Object.defineProperty 不能直接监听数组内部的变化,那么数组内容变化应该怎么操作呢?Vue 主要采用的是改装数组方法的方式(push、pop、shift、unshift、splice、sort、reverse),在保留其原有功能的前提下,将其新添加的项变为响应式的。
除了改装其原有数组方法外,Observer 函数中也将增加对数组的处理逻辑。
二、依赖收集
目前对象中所有的属性已经变成可帧听状态,下一步就进入了依赖收集阶段,其整个流程如下所示:
其实看了这张神图后,由于能力有限还不是很理解,经过自己的拆分,认为可以分成两个步骤去理解。
getter 中(Object.defineProperty 中的 get 属性)进行收集依赖后的状态
2. 紧接着就是触发依赖,该过程是在 setter 中进行,当触发依赖时所存储在 Dep 中的所有 Watcher 均会被通知并执行,通知其关联的组件更新,例如数据更新的位置是与 Dep1 所关联的数据,则其上的 Watcher1、Watcher2、WatcherN 均会被通知并执行。
说了这么多,其中最核心的内容无外乎 Dep 类、Watcher 类、defineReactive 函数中的 set 和 get 函数。
2.1 Dep 类
Dep 类用于管理依赖,包含依赖的添加、删除、发送消息,是一个典型的观察者模式。
2.2 Watcher 类
Watcher 类的实例就是依赖,在其实例化阶段会作为依赖存储到 Dep 中,在对应的数据改变时会更新与该数据相关的 Watcher 实例,进行对应任务的执行,更新对应组件。
2.3 defineReactive 函数中的 set 和 get 函数
Object.defineProperty 中的 getter 阶段进行收集依赖,setter 阶段触发依赖。
参考文献
本文是笔者看了邵山欢老师的视频后做的一次总结,邵老师讲的真心很好,爆赞。
1.如果觉得这篇文章还不错,来个分享、点赞吧,让更多的人也看到
2.关注公众号执鸢者,领取学习资料(前端“多兵种”资料),定期为你推送原创深度好文
版权声明: 本文为 InfoQ 作者【执鸢者】的原创文章。
原文链接:【http://xie.infoq.cn/article/687b42324fb22a60eb5d3f940】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论