《Vue进阶教程》第十三课:实现依赖收集

embedded/2024/12/20 8:06:24/

 往期内容:

《Vue进阶教程》第三课:Vue响应式原理

《Vue进阶教程》第四课:reactive()函数详解

《Vue进阶教程》第五课:ref()函数详解(重点)

《Vue进阶教程》第六课:computed()函数详解(上)

《Vue进阶教程》第七课:computed()函数详解(下)

《Vue进阶教程》第八课:watch()函数的基本使用

《Vue进阶教程》第九课:watch()函数的高级使用

《Vue进阶教程》第十课:其它函数

《Vue进阶教程》第十一课:响应式系统介绍

《Vue进阶教程》第十二课:实现一对多

1) 为什么要依赖收集

前面, 我们并没有区分不同属性对应的副作用函数, 而是全部放入到副作用桶里.

示例

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><script>// 定义一个副作用桶bucketconst bucket = new Set() // 修改/*** 定义响应式*  @param [object] : 普通对象*  @return [Proxy] : 代理对象*/function reactive(data) {// 如果传入的data不是一个普通对象, 不处理if (typeof data !== 'object' || data == null) returnreturn new Proxy(data, {get(target, key) {// console.log(`自定义访问${key}`)return target[key]},set(target, key, value) {// console.log(`自定义设置${key}=${value}`)target[key] = value // 先更新值bucket.forEach((fn) => fn())return true},})}const pState = reactive({ name: 'hello', age: 20 })function effectName() {console.log('effectName...', pState.name)}bucket.add(effectName)function effectAge() {console.log('effectAge...', pState.age)}bucket.add(effectAge)setTimeout(() => {pState.name = 'brojie'}, 1000)</script></body>
</html>

接下来我们思考这样的问题
🤔思考
如果一个副作用函数effectName只引用了name
另一个副作用函数effectAge只引用了age
理论上, 更新name只需要重新执行effectName而不需要重新执行effectAge
换句话说, 依赖收集就是建立属性与副作用函数的对应关系

2) 实现思路


1将当前副作用函数保存到一个全局变量
2当执行副作用函数时, 会触发代理对象的自定义get操作
3在get操作时, 将全局变量中保存的函数添加到副作用桶


3) 具体实现

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><script>// 定义一个副作用桶bucketconst bucket = new Set() // 修改// 定义一个全局变量, 作于保存 `当前副作用函数`let activeEffect = null/*** 定义响应式*  @param [object] : 普通对象*  @return [Proxy] : 代理对象*/function reactive(data) {// 如果传入的data不是一个普通对象, 不处理if (typeof data !== 'object' || data == null) returnreturn new Proxy(data, {get(target, key) {// console.log(`自定义访问${key}`)if (activeEffect != null) {bucket.add(activeEffect)}return target[key]},set(target, key, value) {// console.log(`自定义设置${key}=${value}`)target[key] = value // 先更新值bucket.forEach((fn) => fn())return true},})}const pState = reactive({ name: 'hello', age: 20 })// 定义副作用函数function effectName() {console.log('effectName...', pState.name)}// 将副作用函数保存到全局变量中activeEffect = effectName// 执行副作用函数effectName()// 重置全局变量activeEffect = nullsetTimeout(() => {pState.name = 'brojie'}, 1000)</script></body>
</html>

4) 优化

接下来, 我们优化一下, 封装一个注册函数, 方便注册副作用函数

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><script>// 定义一个副作用桶bucketconst bucket = new Set() // 修改// 定义一个全局变量, 作于保存 `当前副作用函数`let activeEffect = null/*** 定义响应式*  @param [object] : 普通对象*  @return [Proxy] : 代理对象*/function reactive(data) {// 如果传入的data不是一个普通对象, 不处理if (typeof data !== 'object' || data == null) returnreturn new Proxy(data, {get(target, key) {// console.log(`自定义访问${key}`)if (activeEffect != null) {bucket.add(activeEffect)}return target[key]},set(target, key, value) {// console.log(`自定义设置${key}=${value}`)target[key] = value // 先更新值bucket.forEach((fn) => fn())return true},})}/*** 注册副作用函数* @params [function]: 要注册的 副作用函数*/function registEffect(fn) {if (typeof fn !== 'function') return// 将当前注册的副作用函数 保存 到全局变量中activeEffect = fn// 执行当前副作用函数, 收集依赖fn()// 重置全局变量activeEffect = null}const pState = reactive({ name: 'hello', age: 20 })registEffect(function effectName() {console.log('effectName...', pState.name)})setTimeout(() => {pState.name = 'brojie'}, 1000)</script></body>
</html>

提示

源码里注册副作用函数的函数名就叫effect

这里我们重在理解函数的功能, 不用去纠结名字


http://www.ppmy.cn/embedded/147225.html

相关文章

Oracle 中什么情况下 可以使用 EXISTS 替代 IN 提高查询效率

为什么 EXISTS 更高效&#xff1f; EXISTS 提前终止&#xff1a; EXISTS 一旦在子查询中找到第一个匹配项&#xff0c;就会立即返回 TRUE&#xff0c;不再继续扫描子查询中的其他记录。IN 必须扫描整个子查询的结果集&#xff0c;将所有结果与主查询的每一行进行对比。大数据集…

WebRTC服务质量(04)- 重传机制(01) RTX NACK概述

WebRTC服务质量&#xff08;01&#xff09;- Qos概述 WebRTC服务质量&#xff08;02&#xff09;- RTP协议 WebRTC服务质量&#xff08;03&#xff09;- RTCP协议 WebRTC服务质量&#xff08;04&#xff09;- 重传机制&#xff08;01) RTX NACK概述 WebRTC服务质量&#xff08;…

智能光学计算成像技术与应用

智能光学计算成像是一个将人工智能&#xff08;AI&#xff09;与光学成像技术相结合的前沿领域&#xff0c;它通过深度学习、光学神经网络、超表面光学&#xff08;metaphotonics&#xff09;、全息技术和量子光学等技术&#xff0c;推动光学成像技术的发展。以下是智能光学计算…

springcloud-gateway获取应用响应信息乱码

客户端通过springcloud gateway跳转访问tongweb上的应用&#xff0c;接口响应信息乱码。使用postman直接访问tongweb上的应用&#xff0c;响应信息显示正常。 用户gateway中自定义了实现GlobalFilter的Filter类&#xff0c;在该类中获取了上游应用接口的响应信息&#xff0c;直…

BlueLM:以2.6万亿token铸就7B参数超大规模语言模型

一、介绍 BlueLM 是由 vivo AI 全球研究院自主研发的大规模预训练语言模型&#xff0c;本次发布包含 7B 基础 (base) 模型和 7B 对话 (chat) 模型&#xff0c;同时我们开源了支持 32K 的长文本基础 (base) 模型和对话 (chat) 模型。 更大量的优质数据 &#xff1a;高质量语料…

推动数字金融高质量发展行动方案之数据安全解读

一、《方案》中的数据安全要求 2024年11月27日,中国人民银行等七部门联合印发《推动数字金融高质量发展行动方案》(以下简称《方案》),明确提出系统推进金融机构数字化转型、运用数字技术提升重点领域金融服务质效、夯实数字金融发展基础、完善数字金融治理体系等方面的重…

网络安全(4)_网络层安全IPSec

5. 网络层安全IPSec 5.1 IPSec协议 &#xff08;1&#xff09;前面使用Outlook进行数字签名和数字加密是应用层实现的安全。安全套接字实现的安全是在应用层和传输层之间插入了一层来实现数据通信安全。而IPSec是网络层实现的安全。不需要应用程序的支持&#xff0c;只要配置…

使用 Puppeteer 快速上手 Node.js 爬虫

使用 Puppeteer 库通过自动化浏览器来访问百度图片搜索&#xff0c;并在搜索结果中下载图片。代码分为两部分&#xff1a; 自动化浏览器任务&#xff1a;使用 Puppeteer 浏览百度图片搜索并获取图片 URL。图片下载&#xff1a;检查图片 URL 类型&#xff08;base64 或 URL&…