【Vue3源码学习】— CH2.4 Dep:依赖管理新思路

在Vue 3中,Dep不再是一个类,而是一种通过Map实现的依赖追踪方式,这代表了Vue响应式系统对依赖管理的新思路。与Vue 2相比,这种方法在性能和内存使用上带来了显著的优化。

1. Vue 2中的依赖管理

在Vue 2中,每个响应式属性都有一个Dep实例与之对应。
Dep是一个类,它内部维护了一个订阅者列表,这个列表是由副作用函数(如观察者、计算属性等)组成的。当一个响应式属性被读取时,当前激活的副作用函数会被添加到这个属性的Dep实例中;当属性发生变化时,Dep实例会通知所有订阅者重新计算或重新渲染。
这种方式在概念上清晰,易于理解,但每个响应式属性都需要创建一个Dep实例,在大规模应用中可能造成内存压力。

class Dep {
  constructor() {
    this.subs = []; // 订阅者列表
  }
  // 添加订阅者
  addSub(sub) {
    this.subs.push(sub);
  }
  // 通知所有订阅者
  notify() {
    this.subs.forEach(sub => sub.update());
  }
}

2. Vue 3的优化:Dep类型的转变

Vue 3中的Dep是一个使用Map结构来追踪副作用函数和其调用次数的类型别名。这种设计减少了对象创建,利用原生结构提高了性能。

/**
 * ts类型别名声明:它使用了交叉类型(&)来组合多个类型
 */
export type Dep = Map<ReactiveEffect, number> & {
  cleanup: () => void
  computed?: ComputedRefImpl<any>
}

解析:

2.1 Map<ReactiveEffect, number>:

Dep现在是一个Map,其中键是ReactiveEffect类型(副作用函数),值是number类型,用来追踪其调用次数,这有助于优化重复的副作用调用。

2.2 &:

这个符号在TypeScript中表示交叉类型,用来组合多个类型到一个类型中。这意味着Dep类型既具有Map<ReactiveEffect, number>的所有特性,又具有后面定义的对象类型的特性。

2.3 { cleanup: () => void; computed?: ComputedRefImpl; }:

这部分定义了一个带有两个属性的对象类型,提供了额外的管理功能:
**- cleanup: () => void:**表示一个名为cleanup的方法,这个方法没有参数并且返回void。这个方法的用途通常是进行清理操作,比如在依赖关系被移除时清理不再需要的副作用函数。
**- computed?: ComputedRefImpl:**表示一个可选的名为computed的属性,它的类型是ComputedRefImpl。ComputedRefImpl是计算属性的内部实现,这里使用any泛型表示计算属性可以返回任意类型的值。属性前的?符号表示这个属性是可选的,也就是说在Dep类型的对象中,computed属性可以不存在。

3. Vue 3的依赖管理机制

Vue 3采用Proxy和Reflect API,结合WeakMap和Map,实现了更高效的依赖管理。targetMap是全局的依赖映射表,它存储了响应式对象的每个属性与依赖关系的映射。

/**
 * reactiveEffect.ts文件:
 */
// targetMap 是一个全局的 WeakMap,用来存储每个响应式对象与它的属性依赖关系的映射。
const targetMap = new WeakMap<object, KeyToDepMap>()

//对于每个响应式对象(target),targetMap 关联一个 KeyToDepMap,它是一个 Map,其中的键是属性名,值是一个Dep类型。
type KeyToDepMap = Map<any, Dep>  

4. 性能考虑

减少内存使用:

避免了为每个响应式属性创建的Dep对象实例,降低内存占用。

优化垃圾回收:

使用WeakMap,未被引用的响应式对象及其依赖关系可以被自动回收,而不需要维护额外的引用,有利于垃圾回收器更高效地回收不再使用的响应式数据。

利用原生结构:

Map的操作(查找、插入和删除)性能优于自定义结构,加快了依赖追踪和更新触发。

5. 对比总结

Vue 3的依赖管理策略通过全局的targetMap和依赖类型的改进,提升了响应式系统的性能和效率,特别是在处理大规模数据和复杂应用时。这种设计还为Vue 3带来了更好的TypeScript支持和现代JavaScript特性的利用,展现了Vue团队对框架性能和开发体验的持续优化。

在深入理解了Dep类型和Vue 3的依赖管理机制之后,我们对于如何在Reactive对象的属性get和set操作中实施track和trigger有了更清晰的视角。让我们下一章中继续探索!

在这里插入图片描述

  • 33
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值