vue2响应式原理

响应式是干嘛的?怎么实现响应式

响应式数据的最终目标,是当对象本身或对象的属性发生变化时,会运行一些函数,最常见的就是render函数

在具体表现上,具体会用到几个核心部件

  1. Observer
  2. Dep
  3. Watcher
  4. Scheduler

Observer

Observer的目标非常简单,就是把一个普通的对象变为响应式对象
为了实现这一点,Observer把对象的每个属性通过 object.defineProperty转换带有getter,setter属性,这样,当访问或设置属性时就有机会做一些别的事

在这里插入图片描述

Observer是vue内部的构造器,我们可以通过vue提供的静态方法vue.Observer ( object )间接使用该功能

在组件生命周期中,这件事发生在beforCreate之后,created之前

具体实现上,他会递归遍历对象的所有属性,以完成深度的属性转换

由于遍历只能遍历到对象的当前属性,因此无法检测到将来动态增加和更新的属性,因此,vue提供了 $set 和 $delete 两个实例方法,让开发者通过这两个实例方法对已有响应式对象添加或删除属性

对于数组,vue会更改它的隐式原型,之所以这样做,是vue需要监听那些可能改变数组内容的方法

在这里插入图片描述
总之,obServer的目的,就是要让一个对象,他的属性的读取、赋值、以及数组内容的变化都要被vue感知到

Dep

这里有两个问题没解决,就是读取属性时要做什么事,而属性变化时要做什么事,这个问题需要依赖Dep去解决
Dep的含义是Dependency,表示依赖的意思
vue会对每个响应式对象的属性、对象本身、数组本身创建一个Dep实例,每个Dep实例都有能力做以下两件事:

  1. 记录依赖:是谁用到了我
  2. 派发更新:我变了,我需要通知那些用到我的人

当读取响应式对象的某个属性时,它会进行依赖收集:有人用到了我
当改变某个属性时,它会派发更新:那些用我的人听好了,我变了

在这里插入图片描述

Watcher

这里又出现一个问题,dep如何知道谁在用我?

要解决这个问题,就要依赖到Watcher

当某个函数用到了响应式数据,响应式数据无法知道哪些函数在用自己

因此,vue通过一种巧妙的方法来解决这个问题

我们不要直接执行函数,而是把函数交给一个叫Watcher的东西去执行,Watcher是一个对象,每个这样的函数都会创建一个Watcher,通过Watcher去执行

Watcher会设置一个全局变量,让全局变量记录当前执行的Watcher等于自己,然后再去执行函数,在函数执行过程中,如果发生了依赖,记录dep.depend(), 那么dep就会把这个全局变量记录下来,表示,有一个watcher用到了我这个属性

当dep进行派发更新时,它会通知之前记录的所有watcher:我变了
在这里插入图片描述

每个vue组件实例,都至少对应一个Watcher,该Watcher记录了该组件的render函数

Watcher首先会把render函数运行一次以收集依赖,于是那些在render函数中的响应式数据会记录这个Watcher

当数据变化时,dep就会通知该Watcher,而Watcher会重新运行render函数,从而让界面重新渲染同时重新记录当前的依赖

Scheduler

现在还剩最后一个问题,就是Dep通知Watcher后,如果Watcher执行重运行对应的函数,就可能导致函数频繁运行,从而导致效率低下,试想,如果一个交给Watcher的函数,它里面用到了属性a、b、c、d, 那么a、b、c、d属性都会记录依赖,于是下面的代码将触发四次更新:

state.a = "new data";
state.b = "new data";
state.c = "new data";
state.d = "new data";

这样显然是不适合的,因此,Watcher收到派发更新的通知时,不会立即执行对应函数,而是把自己交给一个叫调度器的东西

调度器维护一个执行队列,该队列同一个Watcher仅会存在一次,队列中的watcher不是立即执行,它通常会通过一个叫nextTick的工具方法,把这些需要执行的Watcher放到事件循环的微队列中,nextTick的具体做法是通过promise完成的

也就是说,响应式数据发生变化时,render函数的执行是异步的,并且在微队列中

总体流程

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值