2024-09-11 10:55:44 +08:00

112 lines
5.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Vue2响应式回顾
>面试题:说一说 Vue3 响应式相较于 Vue2 是否有改变?如果有,那么说一下具体有哪些改变?
**观察者模式**
生活中的观察者模式:
假设顾客对新型号的手机感兴趣,但是目前商店还没到货,那么顾客及时如何买到新型号的手机?
1. 顾客每天去一趟商场 🙅
2. 商品到货后没所有顾客发出通知 🙅
<img src="https://xiejie-typora.oss-cn-chengdu.aliyuncs.com/2024-03-22-074632.png" alt="image-20240322154631735" style="zoom:50%;" />
我们似乎遇到了一个矛盾:要么让顾客浪费时间检查产品是否到货,要么让商店浪费资源去通知没有需求的顾客。
解决方案其实很简单让有需求的顾客watcher主动订阅即可之后商店dep只需要给订阅了用户发送通知。
**Vue2响应式工作机制**
1. data 中的数据会被 Vue 遍历生成 getter 和 setter这样一来当访问或设置属性时Vue 就有机会做一些别的事情。
2. 每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher从而使它关联的组件重新渲染。
<img src="https://xiejie-typora.oss-cn-chengdu.aliyuncs.com/2024-09-01-074111.png" alt="image-20240901154111493" style="zoom:40%;" />
几个比较重要的点:
1. 劫持数据:通过 Object.defineProperty 方法来做数据劫持,生成 getter 和 setter 从而让获取/设置值的时候可以做一些其他的事情。
2. 发布者:记录依赖,也就是数据和 watcher 之间的映射关系
3. 观察者watcher 会被发布者记录,数据发生变化的时候,发布者会会通知 watcher之后 watcher 执行相应的处理
**劫持数据**
劫持数据对象,是 Observer 的工作,它的目标很简单,就是把一个普通的对象转换为响应式的对象
为了实现这一点Observer 把对象的每个属性通过 Object.defineProperty 转换为带有 getter 和 setter 的属性这样一来当访问或设置属性时Vue 就有机会做一些别的事情。
<img src="https://xiejie-typora.oss-cn-chengdu.aliyuncs.com/2024-09-01-052809.png" alt="20210226153448" style="zoom:67%;" />
Observer 是 Vue 内部的构造器,我们可以通过 Vue 提供的静态方法 Vue.observable( object ) 间接的使用该功能。
在组件生命周期中,这件事发生在 beforeCreate 之后created 之前。
具体实现上,**它会递归遍历对象的所有属性,以完成深度的属性转换**。由于遍历时只能遍历到对象的当前属性,因此无法监测到将来动态增加或删除的属性,因此 Vue 提供了 $set 和 $delete 两个实例方法让开发者通过这两个实例方法对已有响应式对象添加或删除属性。对于数组Vue 会更改它的隐式原型,之所以这样做,是因为 Vue 需要监听那些可能改变数组内容的方法。
<img src="https://xiejie-typora.oss-cn-chengdu.aliyuncs.com/2024-09-01-052949.png" alt="20210226154624" style="zoom:67%;" />
总之Observer 的目标,就是要让一个对象,它属性的读取、赋值,内部数组的变化都要能够被 Vue 感知到。
**发布者(商店)**
发布者,也被称之为依赖管理器,对应英文 Dependency简称 Dep.
其中最核心的两个功能:
- 能够添加观察者:当读取响应式对象的某个属性时,它会进行依赖收集
- 能够通知观察者:当改变某个属性时(商品发售了),它会派发更新(通知所有顾客)
<img src="https://xiejie-typora.oss-cn-chengdu.aliyuncs.com/2024-09-01-053233.png" alt="20210226155852" style="zoom:67%;" />
**观察者**
当依赖的数据发生变化时,发布者会通知每一个观察者,而观察者需要调用 update 来更新数据。
**scheduler**
Vue2 内部实现中,还存在一个 Scheduler因为Dep 通知 watcher 之后,如果 watcher 执行重运行对应的函数,就有可能导致函数频繁运行,从而导致效率低下
试想,如果一个交给 watcher 的函数,它里面用到了属性 a、b、c、d那么 a、b、c、d 属性都会记录依赖,于是下面的代码将触发 4 次更新:
```js
state.a = "new data";
state.b = "new data";
state.c = "new data";
state.d = "new data";
```
这样显然是不合适的因此watcher 收到派发更新的通知后,实际上不是立即执行对应函数,而是把自己交给一个叫调度器的东西
调度器维护一个执行队列,该**队列同一个 watcher 仅会存在一次,队列中的 watcher 不是立即执行,它会通过一个叫做 nextTick 的工具方法,把这些需要执行的 watcher 放入到事件循环的微队列中**也就是说当响应式数据变化时render 函数的执行是**异步**的,并且在**微队列**中。
**Vue2响应式整体流程**
![20210226163936](https://xiejie-typora.oss-cn-chengdu.aliyuncs.com/2024-09-01-053804.png)
几个核心部件:
1. Observer用于劫持数据对象把对象的每个属性通过 Object.defineProperty 转换为带有 getter 和 setter 的属性
2. Dep(商店):发布者,也被称之为依赖管理器
- 能够添加观察者:当读取响应式对象的某个属性时,它会进行依赖收集
- 能够通知观察者:当改变某个属性时,它会派发更新
3. Watcher顾客负责具体的更新操作可以理解为用户收到商场的邮件后自身要做什么事情
4. Scheduler负责调度。
---
-EOF-