【Vue3源码】第二章 effect功能的完善补充
【Vue3源码】第二章 effect功能的完善补充
前言
上一章节我们实现了effect函数的功能stop和onstop,这次来优化下stop功能。
优化stop功能
之前我们的单元测试中,stop已经可以成功停止了响应式更新(清空了收集到的dep依赖)
stop功能其实还存在很大的问题,就是不能停止对象中的++操作
为什么呢?
看个例子
let user = { age : 10 }user.age++
//++是一个语法糖,他在js中的表现为
//user.age = user.age + 1
看了例子我们就可以明白为什么stop功能会存在漏洞了,因为user.age = user.age + 1 这句代码在响应式中user.age + 1会先触发get捕获器然后 +1触发set捕获器
那么get捕获器又会重新收集依赖,我们之前stop清空的依赖就又回来了导致无法stop响应式更新这个漏洞出现
怎么解决这个问题?
我们可以从run方法和track函数切入,只要判断调用run方法track就去收集依赖,如果是stop调用的run方法,track函数就不要去收集依赖即可。
1.单元测试代码
进入effect.spec.ts文件
还是使用之前的stop单元测试代码即可
我们把obj.prop = 3 改为 obj.prop++
it("stop",() => {let dummy;const obj = reactive({prop:1})const runner = effect(() => {dummy = obj.prop})obj.prop = 2expect(dummy).toBe(2)stop(runner)// 修改// obj.prop = 3obj.prop++expect(dummy).toBe(2)//stopped effect should still be manually callablerunner()expect(dummy).toBe(3)})
2.优化run方法
进入effect.ts文件
我们再通过新增一个全局变量shouldTrack,作为开关,去有效的控制track进行依赖收集
//新增
let shouldTrack;class ReactiveEffect {private _fn;active = true;deps = [];onStop?: () => void;constructor(fn, public scheduler?) {this._fn = fn;this.scheduler = scheduler;}//修改run() {// 3.因为默认shouldTrack= false// 4.调用了stop的时候直接执行了this._fn()// 5.但是shouldTrack是关上的if (!this.active) {return this._fn()}// 1.run的时候才会开启开关shouldTrack = true;activeEffect = this;const result = this._fn();// 2.reset,生成ReactiveEffect类时,我们都会默认调用 _effect.run()方法,所以默认执行完this._fn()后都会重置 shouldTrack = falseshouldTrack = false;return result}stop() {if (this.active) {clearupEffect(this);if (this.onStop) {this.onStop()}this.active = false}}
}
调用run()方法的时候会去开启shouldTrack开关,因为生成ReactiveEffect类时我们都会默认调用 _effect.run()方法,所以默认的 this._fn()执行完后都会使shouldTrack 重置为 shouldTrack = false

那么就出现以下两种情况:
正常调用effect.run() 和 stop调用 effect.run()
他们通过shouldTrack这个开关就可以识别,所以我们可以通过shouldTrack全局变量去判断track是否该触发依赖收集
3.优化track函数
vue3源码就是通过shouldTrack和activeEffect两个开关去控制track函数执行,来达到可以控制的依赖收集功能
//依赖收集
export function track(target, key) {// 6.如果是stop调用那么在触发track时,因为shouldTrack是false,所以track就不能执行了// 7.如果是run()调用那么在触发track时,因为shouldTrack是true,所以可以执行track逻辑,等track结束,才把shouldTrack = falseif (activeEffect && shouldTrack) {let depsMap = targetMap.get(target);if (!depsMap) {depsMap = new Map();targetMap.set(target, depsMap);}let dep = depsMap.get(key);if (!dep) {dep = new Set();depsMap.set(key, dep);}dep.add(activeEffect);//浅拷贝反向收集到depactiveEffect.deps.push(dep);}
}
4.优化clearupEffect函数
用for代替了forEach提高性能,如果清空了依赖我们就把deps的length也清空,最大程度的优化性能
function clearupEffect(effect) {const { deps } = effectif (deps.length) {for (let i = 0; i < deps.length; i++) {//因为是浅拷贝收集到的dep,所以这里删掉对应的dep就没有了,没有dep(二级分类)自然就无法触发run方法!deps[i].delete(effect)}deps.length = 0}
}
5.代码运行流程图
上面就基本把stop的漏洞修复了,我们来看下run方法运行和stop方法运行时的区别

通过所有测试!

相关文章:
【Vue3源码】第二章 effect功能的完善补充
【Vue3源码】第二章 effect功能的完善补充 前言 上一章节我们实现了effect函数的功能stop和onstop,这次来优化下stop功能。 优化stop功能 之前我们的单元测试中,stop已经可以成功停止了响应式更新(清空了收集到的dep依赖) st…...
CHAPTER 2 Web Server - apache(httpd)
Web Server - httpd2.1 http2.1.1 协议版本2.1.2 http报文2.1.3 web资源(web resource)2.1.4 一次完整的http请求处理过程2.1.5 接收请求的模型2.2 httpd配置2.2.1 MPM(多进程处理模块)1. 工作模式2. 切换MPM3. MPM参数配置2.2.2 主配置文件1. 基本配置2. 站点访问控制常见机制…...
【Vagrant】下载安装与基本操作
文章目录概述软件安装安装VirtualBox安装Vagrant配置环境用Vagrant创建一个VMVagrantfile文件配置常用命令概述 Vagrant是一个创建虚拟机的技术,是用来创建和管理虚拟机的工具,本身自己并不能创建管理虚拟机。创建和管理虚拟机必须依赖于其他的虚拟化技…...
常用类(五)System类
(1)System类常见方法和案例: (1)exit:退出当前程序 我们设计的代码如下所示: package com.ypl.System_;public class System_ {public static void main(String[] args) {//exit: 退出当前程序System.out.println("ok1"…...
Navicat Premium 安装 注册
Navicat Premium 一.Navicat Premium的安装 1.暂时关闭windows的病毒与威胁防护弄完再开,之后安装打开过程中弹窗所有警告全部允许,不然会被拦住 2.下载安装包,解压 链接:https://pan.baidu.com/s/1X24VPC4xq586YdsnasE5JA?pwdu4vi 提取码…...
回溯算法总结
首先回溯算法本身还是一个纯暴力的算法,只是回溯过程可能比较抽象,导致大家总是感觉看到的相关题目做的不是很顺畅,回溯算法一般来说解决的题目有以下几类:组合问题:lq77、lq17、lq39、lq40、lq216、切割问题ÿ…...
ccc-pytorch-基础操作(2)
文章目录1.类型判断isinstance2.Dimension实例3.Tensor常用操作4.索引和切片5.Tensor维度变换6.Broadcast自动扩展7.合并与分割8.基本运算9.统计属性10.高阶OP大伙都这么聪明,注释就只写最关键的咯1.类型判断isinstance 常见类型如下: a torch.randn(…...
独居老人一键式报警器
盾王居家养老一键式报警系统,居家养老一键式报警设备 ,一键通紧急呼救设备,一键通紧急呼救系统,一键通紧急呼救器 ,一键通紧急呼救终端,一键通紧急呼救主机终端产品简介: 老人呼叫系统主要应用于…...
软考案例分析题精选
试题一:阅读下列说明,回答问题1至问题4,将解答填入答题纸的对应栏内。某公司中标了一个软件开发项目,项目经理根据以往的经验估算了开发过程中各项任务需要的工期及预算成本,如下表所示:任务紧前任务工期PV…...
基于SpringBoot+vue的无偿献血后台管理系统
基于SpringBootvue的无偿献血后台管理系统 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取项目下载方式🍅 一、项目背…...
详解js在事件中,如何传递复杂数据类型(数组,对象,函数)
文章目录 前言一、何谓预编译,变量提升?二、复杂数据类型的传递 1.数组2.对象3.函数总结前言 在JavaScript这门编程语言学习中,如何传参,什么是变量提升,js代码预编译等等。要想成为一名优秀的js高手,这些内…...
高并发架构 第一章大型网站数据演化——核心解释与说明。大型网站技术架构——核心原理与案例分析
大型网站架构烟花发展历程1.1.1初始阶段的网站构架1.1.2应用服务和数据服务分离1.1.3使用缓存改善网络性能1.1.4使用应用服务器集群改善网站的并发处理能力1.1.5数据库读写分离1.1.6使用反向代理和cdn加速网站相应1.1.1初始阶段的网站构架 大型网站都是由小型网站一步步发展而…...
VPP接口INPUT节点运行数据
在设置virtio接口接收/发送队列函数的最后,更新接口的运行数据。 void virtio_vring_set_rx_queues (vlib_main_t *vm, virtio_if_t *vif) { ...vnet_hw_if_update_runtime_data (vnm, vif->hw_if_index); } void virtio_vring_set_tx_queues (vlib_main_t *vm,…...
RabbitMQ学习(九):延迟队列
一、延迟队列概念延时队列中,队列内部是有序的,最重要的特性就体现在它的延时属性上,延时队列中的元素是希望 在指定时间到了以后或之前取出和处理。简单来说,延时队列就是用来存放需要在指定时间内被处理的 元素的队列。其实延迟…...
TCP并发服务器(多进程与多线程)
欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 TCP并发服务器(多进程与多线程)1. 多进程并发服务器(1)…...
第1章 Memcached 教程
Memcached是一个自由开源的,高性能,分布式内存对象缓存系统。 Memcached是以LiveJournal旗下Danga Interactive公司的Brad Fitzpatric为首开发的一款软件。现在已成为mixi、hatena、Facebook、Vox、LiveJournal等众多服务中提高Web应用扩展性的重要因素…...
【2022.12.9】Lammps+Python 在计算g6(r)时遇到的问题
目录写在前面绘制g6( r )执行步骤【updated】如何检查图像的正确性:不是编程问题,而是数学问题的一个小bug废稿2则:写在前面 全部log: 【2022.11.16】LammpsPythonMATLAB在绘制维诺图时遇到的问题 绘制g6( r )执行步骤【updated…...
MySQL使用C语言连接
文章目录MySQL使用C语言连接引入库下载库文件在项目中使用库使用库连接数据库下发SQL请求获取查询结果MySQL使用C语言连接 引入库 要使用C语言连接MySQL,需要使用MySQL官网提供的库。 下载库文件 下载库文件 首先,进入MySQL官网,选择DEVEL…...
JavaScript随手笔记---比较两个数组差异
💌 所属专栏:【JavaScript随手笔记】 😀 作 者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! &#…...
【C++修炼之路】21.红黑树封装map和set
每一个不曾起舞的日子都是对生命的辜负 红黑树封装map和set前言一.改良红黑树的数据域结构1.1 改良后的结点1.2 改良后的类二. 封装的set和map2.1 set.h2.2 map.h三. 迭代器3.1 迭代器封装3.2 const迭代器四.完整代码实现4.1 RBTree.h4.2 set.h4.3 map.h4.4 Test.cpp前言 上一节…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...
黑马Mybatis
Mybatis 表现层:页面展示 业务层:逻辑处理 持久层:持久数据化保存 在这里插入图片描述 Mybatis快速入门 函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
