阅读 85

Vue3 响应式原理探索Part 1 - 20行代码实现响应式

“这是我参与更文挑战的第2天,活动详情查看: 更文挑战

响应式

当我们用 excel 的时候,当输入的值变化时(width、height),输出的值(size)也会自动变化。

size.png

这种情况是响应式很好的例子。按vue 官方文档的说法:

响应性是一种允许我们以声明式的方式去适应变化的一种编程范例。

但实际我们在写 JavaScript 代码时并不是这样的,并不能简单做到响应式,如下所示:

let width = 4
let height = 5
let size = width * height

// size
// 20

width = 5

// size
// 20

height = 6

// size
// 20
复制代码

当改变 width、height 时, size 并不会自动再重新计算。需要用一些机制来实现响应式。

我们会思考,如果将 size = width * height 这个公式设置为一个函数,当 widthheight 变化时,去通知我们的代码重新执行一下这个函数,是不是就好了。

如果再进一步思考发现,其实有以下问题:

  • 如何感知到值的变化
  • 值变化时,该执行哪些函数,是求 size 还是求周长
  • 值变化时,如何通知函数执行

接下来,我们先看最简单的,当值变化时,我们手动触发一下函数,以获得最新的 size 。

手动触发

首先声明一个函数 effect , 用来计算面积

let param = { width: 4, height: 5 };
let size = 0;

let effect = () => {
    size = param.width * param.height
}

track();
effect();

复制代码

可以看到有一个 track 函数没有实现,顾名思义,这个函数用来做追踪,当值变化时,我们再触发(trigger) 相应的 effect 就好了。

let dep = new Set() // 一个用来存储 effect 类似函数的列表

function track() {
  dep.add(effect) // 存储当前的 effct
}

function trigger() { 
  dep.forEach(effect => effect()) // 执行所有的 effect
}

复制代码

最终的代码示例如下:

let param = { width: 4, height: 5 };
let size = 0;

let effect = () => {
    size = param.width * param.height
}

let dep = new Set() // 一个用来存储 effect 类似函数的列表

function track() {
  dep.add(effect) // 存储当前的 effct
}

function trigger() { 
  dep.forEach(effect => effect()) // 执行所有的 effect
}

track(); // 添加追踪

effect();
console.log(size); // => 20

param.width = 5;
trigger(); // 手动触发
console.log(size); // => 25

param.width = 6;
trigger(); // 手动触发
console.log(size); // => 30

复制代码

bigo,一个傻瓜版本的响应式实现了。

思考或疑惑

弱弱的我现在有两个思考:

  • 每次值变化都需要手动 trigger, 太弱鸡了,为什么不能自动的执行
  • 当应用更复杂时,譬如:
    • param 有 N 个字段,有些字段需要响应,有些字段不需要响应,现在这样做是否太简单粗暴了。
    • 有多个类似 param 的 object 需要响应时,又怎么办,一个 Set 是否太简单了

路漫漫其修远兮。

下篇我们可以学习《Vue3 响应式原理探索Part 2 - 多重结构的响应式

文章分类
前端
文章标签