船长的航行日记
首页
  • 原生能力

    • JavaScript
    • Node
  • 框架能力

    • Vue
    • React
  • 学习笔记

    • 《TypeScript》学习笔记
    • 《JavaScript高程4》学习笔记
  • HTML
  • CSS
  • 最近在读
  • 奇思妙想
  • 读书收获
历史足迹
飞鸽传书
GitHub (opens new window)

captain

心之所向,海的彼岸
首页
  • 原生能力

    • JavaScript
    • Node
  • 框架能力

    • Vue
    • React
  • 学习笔记

    • 《TypeScript》学习笔记
    • 《JavaScript高程4》学习笔记
  • HTML
  • CSS
  • 最近在读
  • 奇思妙想
  • 读书收获
历史足迹
飞鸽传书
GitHub (opens new window)
  • JavaScript

  • node

  • vue组件库开发实践

  • react

  • 学习笔记

  • vue3源码

    • 如何阅读Vue3源码
    • 如何理解响应式
    • 实现手动执行的响应式
    • 实现自动执行的响应式
    • 实现对象多个属性对应的依赖的收集
    • 实现多个对象对应的依赖的收集
    • 实现ref
    • 优化
    • 总结
  • 前端乱炖
  • vue3源码
masongsong
2021-10-16
时间 2分钟
阅读量 0

实现手动执行的响应式

上篇文章,我们粗略的梳理了一遍响应式的概念,看过上篇文章的同学应该明白了什么是响应式,以及我们为什么需要响应式。如果不明白的同学,建议从第一篇文章如何理解响应式原理 (opens new window)开始食用,味道更佳。其实上一篇文章我们基本已经实现了Vue3中响应式原理的雏形,但是还有很多地方不完善,功能也没有完全实现。从这篇文章开始,我们将按照Vue3中响应式实现的思路一步一步手动实现一遍响应式。

首先我们先实现最简单的例子,我们通过手动调用函数的方式实现响应式。有这样一个例子:

let total = 0
let price = 10
let quantity = 2

// 这个就是副作用函数
let effect = () => {
  total = quantity * price
}

// 修改价格 price
price = 20

// 期待总价更新
console.log(total) // 40
1
2
3
4
5
6
7
8
9
10
11
12
13
14

当我们修改价格price的时候,我们希望total的值也能得到更新,也就是effect需要执行。根据上文提到的思想,我们首先需要收集依赖,那这里大家可以想想我们收集的依赖用什么数据结构保存最好呢?还是用上文提到的数组吗?其实也不是不可以,但是我们考虑这样的场景:依赖被重复收集,比如:

const effects = []

let effect = () => {
  // ...
}

// 第一次收集 正常
effects.push(effect)

// 第二次收集 重复依赖 没有必要
effects.push(effect)
1
2
3
4
5
6
7
8
9
10
11

所以说使用数组我们还需要手动去重,那么有更好的集合可以做到自动去重吗?这里可能大家都想到了,那就是使用Set。同时我们定义track函数用来收集依赖,如下:

// 保存effect
let dep = new Set()

// 收集依赖函数
function track() {
  dep.add(effect)
}
1
2
3
4
5
6
7

紧接着,依赖收集好之后,我们还需要一个trigger函数去触发。定义如下:

// 触发依赖函数
function trigger() {
  dep.forEach(effect => effect())
}
1
2
3
4

完整代码如下:

// 保存effect
let dep = new Set()

// 收集依赖函数
function track() {
  console.log('执行了吗')
  dep.add(effect)
}

// 触发依赖函数
function trigger() {
  dep.forEach(effect => effect())
}

// 测试例子
let total = 0
let price = 10
let quantity = 2

// 这个就是副作用函数
let effect = () => {
  total = quantity * price
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

我们测试一下:

price = 20
track()
trigger()
console.log(total) // 40
1
2
3
4

这样我们就实现了手动收集依赖和手动触发依赖的功能。但是,读过第一篇文章的同学肯定知道,我们期望的场景是我们只需要定义需要响应式的数据,而依赖收集和依赖触发是自动执行的,这样才是完美的。这正是我们下一篇文章需要实现的。

编辑 (opens new window)
上次更新: 2021/10/30, 16:48:40
如何理解响应式
实现自动执行的响应式

← 如何理解响应式 实现自动执行的响应式→

最近更新
01
总结
10-19
02
优化
10-16
03
实现ref
10-16
更多文章>
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 生命绿
  • 收获黄
  • 天空蓝
  • 激情红
  • 高贵紫