首页 弘成IT资讯

Vue源码解析-依赖收集还有依赖更新

2019-12-17 弘成IT
分享到:

  一、前言

  我们以前实现过一个简单的响应式逻辑, 但是比起 Vue 的实现那简直就是小孩子的玩具, 在Vue 中, 使用了 observer, watcher, 和 dep 三种对象来实现响应式. 而响应式的属性是具有嵌套特征的复杂对象. 这里涉及到设计模式, 递归与算法等, 可谓是代码的技巧精华所在。

  二、响应式系统

   Template

\

Script

\
 

  在Vue中我们通过双大括号进行插值,我们都知道在Vue中声明的数据都是响应式,什么是响应式,也就是说我们将页面中的数据进行改变的时候,视图会重新渲染,匹配到最新的值。也就是这个原因我们可以脱离页面,不用去操作DOM,只需要关心数据。

  但是问题来了????

  1, Vue是怎么知道数据改变的呢?

  2, 数据在改变的是时候是怎么通知哪些视图更新的呢?

  3, 数据在改变的时候,视图咋知道它什么时候更新呢

  下面我来为同学们答疑解惑??

  三、Object.defineProperty

  我们在js中提供了Object.defineProperty,在Vue3.0没有出现之前,这个方法可以说是Vue的精髓,Vue3.0中借用了proxy实现了数据的双向绑定,由于Vue3.0现在还不够完善,我这里只来说Object.defineProperty。
使用 Object.defineProperty 可以为对象中的每一个属性,设置 get 和 set 方法。

  Object.defineProperty 可以为属性设置很多特性,例如 configurable,enumerable,但是现在不过多解释,重点只放在  get 和 set 。

  get 值是一个函数,当属性被访问时,会触发 get 函数set 值同样是一个函数,当属性被赋值时,会触发 set 函数

举个例子:

\

  我们在读取obj.name的时候会执行get函数,控制台会执行get中的内容,我们给设置obj.name=‘123’的时候会执行set函数,控制台会执行get函数中的内容

  这样我们第一个问题也就迎刃而解了Vue 是怎么知道数据改变的呢?

  恩,Vue 在 属性的 set 方法中做了手脚,因而当数据改变时,触发 属性的 set 方法,Vue 就能知道数据有改变

  四、依赖收集

  简单地说

  data 中的声明的每个属性,都拥有一个数组,保存着 谁依赖(使用)了 它

举个例子:

\

  然后我们在Ttape页面引用了name
 
  此时name对页面Ttape产生了依赖。

  为什么呢?

  因为它知道谁依赖它之后,它就可以在发生改变的时候,通知 依赖它的页面,从而让页面完成更新实际上,会依赖 name 的地方,不只是页面,还会有 computed,watch.... 等等,但是这里我们全部使用页面一词替代这就是依赖收集,把 依赖了我(使用了我的东西),统统保存起来。

  可是,保存在哪里,具体保存的是什么东西,我们这里暂时不深入,我按上面的例子,从Vue 内部打印一份数据供大家简单了解即可

\

  可以看到,name 属性,使用了 一个 dep 保存了 页面Ttape这个依赖,而保存的实际上是 页面Ttape的 Watcher。

  简单说一下,watcher 是什么,每个 Vue 实例都会拥有一个专属的 watcher,可用于实例更新

总结一下

  1、data 中每个声明的属性,都会有一个 专属的依赖收集器 subs

  2、当页面使用到 某个属性时,页面的 watcher 就会被 放到 依赖收集器 subs 中


  数据 是在什么时候进行 收集依赖 的呢?

  答案是,ObjectdefineProperty - get

  当页面 Ttape读取了 name 时,会触发 name 的 get 函数,此时,name 就会保存 页面Ttape 的 watcher 啦

  这便可以回答了我开篇的第二个问题

  数据在改变的是时候是怎么通知哪些视图更新的呢?

  恩,通知那些存在 依赖收集器中的 视图

  五、依赖更新

  依赖更新,就是,通知所有的依赖进行更新

  经过上面的讲解,我们都知道,每个属性都会保存有一个 依赖收集器 subs

  而这个 依赖收集器,是用来在 数据变化时,通知更新的

  数据 是在 什么时候进行 依赖更新 的呢?

  答案是,Object.defineProperty - set

  以上面的 Vue 实例 为例

  当name 改变的时候,name 会遍历自己的 依赖收集器 subs,逐个通知 watcher,让 watcher 完成更新

  这里 name 会通知 页面A,页面A 重新读取新的 name ,然后完成渲染

  这便可以回答了我开篇的第二个问题

  Vue 在数据改变时,视图怎么知道什么时候更新?

  恩,在数据变化触发 set 函数时,通知视图,视图开始更新

  六总结

  1、Object.defineProperty  -  get ,用于 依赖收集

  2、Object.defineProperty  -  set,用于 依赖更新

  3、每个 data 声明的属性,都拥有一个的专属依赖收集器 subs

  4、依赖收集器 subs 保存的依赖是 watcher

  5、watcher 可用于 进行视图更新

弘成IT版权与免责声明
1、凡本网站注明稿件来源为:弘成IT的所有文字、图片和音视频稿件,版权均属本网站所有,任何媒体、网站或个人未经本网协议授权不得转载、链接、转贴或以其他方式复制发表。已经本网协议授权的媒体、网站,在下载使用时必须注明“稿件来源:弘成IT”,违者本网将依法追究责任。
2、本网注明稿件来源为其他媒体的文/图等稿件均为转载稿,本网转载出于非商业性的教育和科研之目的,并不意味着赞同其观点或证实其内容的真实性。如转载稿涉及版权等问题,请作者在两周内速来电或来函联系。