【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前言 上一节…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...
es6+和css3新增的特性有哪些
一:ECMAScript 新特性(ES6) ES6 (2015) - 革命性更新 1,记住的方法,从一个方法里面用到了哪些技术 1,let /const块级作用域声明2,**默认参数**:函数参数可以设置默认值。3&#x…...
Vue 3 + WebSocket 实战:公司通知实时推送功能详解
📢 Vue 3 WebSocket 实战:公司通知实时推送功能详解 📌 收藏 点赞 关注,项目中要用到推送功能时就不怕找不到了! 实时通知是企业系统中常见的功能,比如:管理员发布通知后,所有用户…...
21-Oracle 23 ai-Automatic SQL Plan Management(SPM)
小伙伴们,有没有迁移数据库完毕后或是突然某一天在同一个实例上同样的SQL, 性能不一样了、业务反馈卡顿、业务超时等各种匪夷所思的现状。 于是SPM定位开始,OCM考试中SPM必考。 其他的AWR、ASH、SQLHC、SQLT、SQL profile等换作下一个话题…...
