浅谈Vue框架中的响应式原理

原创 奔跑的小前端 随笔 待整理 217阅读 2018-06-22 15:29:46 举报

众所周知,这几年前端发展的非常迅速,涌现了好几大不错的框架体系,其中Vue.js以入门门槛低实用性高深得广大前端喜爱。今天我们就谈谈Vue.js框架的核心——响应式系统

说到响应式系统,它的原理核心来自于Object.defineProperty,相信大多数人都认识它,但今天也要基本的介绍介绍一下它。

我们可以看看官方的介绍:

然后我们在看看它要那些通用的属性:

知道该方法怎么用的时候,我们就来实现就最基本的响应式系统原理:

这个图片在官方文档上就有,仔细的观察一下,我们不看所有的生命周期,new Vue() => init 这个阶段的时候,数据就开始进行响应式的操作了。

我们定义一个函数,用来表示视图更新,调用这个函数就告诉大家视图更新啦。

接下来我们创建一个defineReactive ,这个方法通过 Object.defineProperty 来实现对对象的响应式操作。

写好这个后我们还需要定义另外一个方法 observer,该方法我们用来遍历修改的对象,对这些对象通过 defineReactive 函数进行相应的处理:

这个时候基本大功告成了,当然真理是需要实践一下,这个时候我们封装一个Vue:

这里我们写一个Vue的构造函数,对options里面的data进行处理,当然,这里面的data就相当于我们经常在vue.js模板里面的写的data。下面我们来new一个Vue的对象进行操作:

这个时候视图就会更新了,这就是vue.js的响应式基本原理。

既然是基本原理,它实现的也是最基本的功能,接下来我们看另外一个例子:

如果我们现在改变c的值: this.c = "全宇宙" 这个时候我们在调用 cb是无用的,但vue里面这时候发生什么?我们不得而知。我们留着疑问看下面一个例子:

假如现在我们有一个全局对象,而且很多vue视图都调用了它:

这时我们做了这样一个操作: echats.options = "line", 这时会发生什么?vue.js又是怎么操作的呢?

根据上面的图我们可以知道,在getter这个阶段会获取到相应Watcher实例对象,然后setter被调用的时候,会通过Watcher重新计算,从而致使它关联的组件模板得以更新。

对比,我们例2和例3,要实现这一系列的操作,单单靠上面我们的基本原理的方法是不行的,所以我们需要改变一下

订阅者Dep

接下来我们来实现一个订阅者,用来存放Watcher实例对象。

这时我们在来实现一个观察者:

观察者Watcher

下面我们在修改一下一开始列子的代码:

通过上面的代码,这个时候我们在回头看例2和例3,当我data.c 改变的时候,这里会发生什么呢?现在我们知道每一个data的属性都对应一个dep,而每一个dep就对应一个或者多个Watcher(多个视图调用的情况),例2中我们改变了data.c,但视图上并没有对象的Watcher,那么它就没法调用addSub方法,所以视图不会更新。当然例3也从中得以理解。 最后贴一下我整理后的所有代码:

总结:

在 observer 的过程中会注册 get 方法,该方法用来进行「依赖收集」。在它的闭包中会有一个 Dep 对象,这个对象用来存放 Watcher 对象的实例。其实「依赖收集」的过程就是把 Watcher 实例存放到对应的 Dep 对象中去。get 方法可以让当前的 Watcher 对象(Dep.target)存放到它的 subs 中(addSub)方法,在数据变化时,set 会调用 Dep 对象的 notify 方法通知它内部所有的 Watcher 对象进行视图更新。

后话: 参考了很多大牛的文章,如果描述的有错,请多多包涵~~

评论 ( 0 )
最新评论
暂无评论

赶紧努力消灭 0 回复