一,前言
上篇,主要介绍了 Vue 的异步更新流程,主要涉及以下几点:
- 为什么要做异步更新
- 异步更新的实现思路
- 数据变更缓存的位置
- 缓存 watcher 更新逻辑
- vm.$nextTick 获取更新后的 dom
- 测试异步更新
本篇,数组的依赖收集
二,数组的依赖收集
1,前情回顾
上一篇,解决了对象的依赖收集:
- 取值时走
getter,进行依赖收集; - 赋值时走
setter,触发视图更新;
但是,数组类型是走不到Object.defineProperty的
// src/observe/index.js
// 简化后的代码...
class Observer {
constructor(value) {
if (isArray(value)) { // 数组类型
this.observeArray(value);
} else {
this.walk(value); // 对象类型,内部调用 defineReactive
}
}
}
那么,数组如何做依赖收集呢?当数组数据更新时,如何触发视图更新?
本篇,继续完善数组的依赖收集;
2,数组的响应式实现
在响应式实现中,数组类型的数据是通过重写能够改变原数组的 7 个方法实现的;
收集数组所依赖的渲染watcher,当数组更新时,触发对应的watcher执行更新操作;
3,数组的依赖收集方案
对象类型的依赖收集方案:为对象的每一个属性都增加一个dep属性用于收集依赖;
那么同理,可以为数组增加dep属性用于收集依赖;
这样一来,当数组更新时,通知数组方法执行视图更新
4,数组依赖收集的入口
当前代码:
// src/observe/index.js
class Observer {
constructor(value) {
// 为每一个对象添加 __ob__
Object.defineProperty(value, '__ob__', {
value:this,
enumerable:false
});
if (isArray(value)) {
value.__proto__ = arrayMethods;
this.observeArray(value);
} else {
this.walk(value);
}
}
对象或数组类型的数据,都会通过new Observer创建observer实例,
所以,Observer构造函数中的value可能是数组,也可能是对象;
在Observer类中,为value添加了__ob__属性(this为当前observer实例),
也就是说,每个对象或数组都具有一个__ob__属性;(对象和数组都有value.__ob__)
那么,就可以在此处,为observer实例添加dep属性;(数组或对象都拥有value.__ob__dep);
// src/observe/index.js
import Dep from "./dep";
class Observer {
constructor(value) {
// 为当前 observer 实例添加 dep 属性
this.dep = new Dep();
Object.defineProperty(value, '__ob__', {
value:this,
enumerable:false
});
if (isArray(value)) {
value.__proto__ = arrayMethods;
this.observeArray(value);
} else {
this.walk(value);
}
}
}
这样一来,无论对象或数组,都可以通过value.__ob__.dep获取到dep,
当数组数据变化时,就可以通过dep中收集的watcher来触发视图更新操作;
5,添加 dep 后,对象的收益
上边,为对象和数组本身都增加一个dep,即value.__ob__.dep;
这种方法,不仅使数组实现了依赖收集和视图更新,也使对象的本身具备了依赖收集的特性;
在之前版本,修改对象中已存在的属性可以触发更新,但新增不存在的属性是不能触发更新的;
根本原因在于,对象中已存在的属性有dep,新增加的属性没有dep,也就无法触发更新;
{a:1, b:2}.__ob__.dep===>{a:1, b:2, c:3}.__ob__.dep
value.__ob__.dep为对象和数组本身添加了一个dep,也就收集了渲染watcher,
这样一来,当为对象新增属性时,就可以利用dep中收集的watcher来触发视图的更新了;
备注:这里也是
Vue.$set()的实现原理;
三,结尾
本篇,主要介绍了数组依赖收集的原理:
- 数组的响应式实现
- 数组的依赖收集方案介绍
- 数组依赖收集的入口
- 添加 dep 后,对象的收益
下一篇,数组依赖收集的实现
更新记录
- 20230208:添加必要的代码示例和注释说明,添加了内容中的代码高亮,添加了“对象收益”的描述分析,更新了文章摘要;