【Vue3源码】第二章 effect功能的完善补充

news2024/9/21 15:52:30

【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 = 2
    expect(dummy).toBe(2)
    stop(runner)
    // 修改
    // obj.prop = 3
    obj.prop++
    expect(dummy).toBe(2)

    //stopped effect should still be manually callable
    runner()
    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 = false

    shouldTrack = 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源码就是通过shouldTrackactiveEffect两个开关去控制track函数执行,来达到可以控制的依赖收集功能

//依赖收集
export function track(target, key) {
  // 6.如果是stop调用那么在触发track时,因为shouldTrack是false,所以track就不能执行了
  // 7.如果是run()调用那么在触发track时,因为shouldTrack是true,所以可以执行track逻辑,等track结束,才把shouldTrack = false
  if (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);
    //浅拷贝反向收集到dep
    activeEffect.deps.push(dep);
  }
}

4.优化clearupEffect函数

用for代替了forEach提高性能,如果清空了依赖我们就把deps的length也清空,最大程度的优化性能

function clearupEffect(effect) {
  const { deps } = effect
  if (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方法运行时的区别

在这里插入图片描述
通过所有测试!
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/357739.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

nginx+php-fpm整体上线k8s集群之后虚拟内存不断上涨原因排查

背景 为了可以更好的管理我们的lnmp集群&#xff0c;打算将原有的php环境整体打包成一个镜像然后上到k8s容器&#xff0c;这样可以不仅使用到k8s的快速扩缩容和管理的好处&#xff0c;而且让机器资源能更好被利用&#xff0c;减少机器数量 问题 当我们将流量从原有的php机器…

Elasticsearch的安装及常用操作

文章目录一、Elasticsearch的介绍1、Elasticsearch索引2、Elasticsearch的介绍二、Elasticsearch的安装1、安装ES服务2、安装kibana3、Docker安装ES4、Docker安装Kibana三、ES的常用操作1、索引操作2、文档操作3、域的属性3.1 index3.2 type3.3 store总结一、Elasticsearch的介…

关于云计算,我们问了ChatGPT 10个问题

ChatGPT懂云计算吗&#xff1f;前些天&#xff0c;我们问了ChatGPT&#xff08;非Plus收费版&#xff09;一些问题。1. 什么是云计算&#xff1f;2. 云计算行业的护城河是什么&#xff1f;3. 什么是云原生&#xff1f;4. 微软Azure与亚马逊AWS的主要区别是什么&#xff1f;5. 为…

你真的会做APP UI自动化测试吗?我敢打赌百分之九十的人都不知道这个思路

目录 前言 一&#xff0c;开发语言选择 二&#xff0c;UI测试框架选择 1&#xff0c;Appium 2&#xff0c;Airtest 3&#xff0c;选择框架 三&#xff0c;单元测试框架选择 四&#xff0c;测试环境搭建 1&#xff0c;测试电脑选择 2&#xff0c;测试手机选择 3&#…

6.关于系统服务的思考—— native vs java

文章目录native服务 以sensor service为例Native 服务java 服务&#xff0c; 以vibrate为例java 服务 以一个demo为例native服务 以sensor service为例 service启动 SystemServer.startBootstrapServices---->>>mSystemServiceManager.startService—>>>Sen…

SQL语句创建视图:

前言 &#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏: &#x1f354;&#x1f35f;&#x1f32f; c语言初阶 &#x1f511;个人信条: &#x1f335;知行合一 &#x1f349;本篇简介:>:介绍数据库中有关视图的知识,参考学校作业. 金句分享:…

基于SpringBoot的在线文档管理系统

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7/8.0 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.3.9 浏…

进程-操作系统结构

进程-操作系统结构 中文仅本人理解&#xff0c;有错误请联系我。 操作系统为不同方面服务&#xff0c;有不同的设计角度。 为用户&#xff1a; 使用 为程序员&#xff1a;创造 程序员需要关注的就是system call接口的调度 file systems&#xff1a;ntfs&#xff0c;ext4 commu…

eclipse快捷开发学习笔记

快速收起java类中的所有代码当类中方法过多时&#xff0c;收起所有方法&#xff0c;可以方便查看注释找到方法右击左侧栏任意行号位置-点击Folding-点击Collapse All效果图如下代码格式化混乱的代码格式化后&#xff0c;方便阅读分析菜单栏-Source-Format效果如下3.查看方法被哪…

Bland-Altman图

介绍 Bland-Altman图是一种一致性评价测量方法&#xff0c;简称BA&#xff0c;常用于医学实验和数据分析。 可使用它检测两组数据的一致性&#xff0c;比如对比新旧两种方法&#xff0c;对比一组实际值和预测值等。相对于校准曲线&#xff0c;它能更好地对比两组数据中每个数据…

Unit Test and Integration Test

Unit Test and Integration Test Background It is the first time that I try to write an article in English. In the past, I didn’t write test code. Just thinking QA is responsible for testing. As a developer, I don’t need to care about tests. Although I …

Robust Self-Augmentation for Named Entity Recognition with Meta Reweighting

摘要 近年来&#xff0c;自我增强成为在低资源场景下提升命名实体识别性能的研究热点。Token substitution and mixup &#xff08;token替换和表征混合&#xff09;是两种有效提升NER性能的自增强方法。明显&#xff0c;自增强方法得到的增强数据可能由潜在的噪声。先前的研究…

【Vue3源码】第四章 实现isReadonly和isReactive

【Vue3源码】第四章 实现isReadonly和isReactive 前言 上一章节我们实现readonly API&#xff0c;并且优化之前写的reactive API。这一章我们实现isReadonly和isReactive两个API。 1、实现isReactive 官网是这么介绍的&#xff1a;检查一个对象是否是由 reactive() 或 shallo…

WebView2 (Chromium) 右键菜单大全

在开发WebView2浏览器时&#xff0c;需要定制右键上下文菜单&#xff0c;但是微软的官方网站上没有详细的菜单&#xff0c;这里整理出来&#xff0c;以方便大家使用。以下是在win11上测试获取的&#xff0c;经过测试win7上稍有不同。一、网页上空白处右键 Target&#xff1a;Pa…

Mybatis Notes

文章目录1 Mybatis 介绍1.1 快速入门2 JDBC2.1 JDBC介绍2.3 JDBC问题分析2.4 Mybatis与JDBC技术对比3 数据库连接池3.1 数据库连接池介绍3.2 数据库连接池产品产品3.3 Druid引入项目4lombok4.1 lombok介绍4.2 lombok使用4.2.1 在pom.xml文件中引入依赖4.2.2 pojo类代码引入1 My…

强化学习 Reinforcement Learning(1) ~ 介绍

1. 强化学习概念和分类 强化学习&#xff0c;Reinforcement Learning 通过价值选行为&#xff1a; Q LearningSarsaDeep Q Network 直接选行为&#xff1a; Policy Gradients 想象环境并从众学习&#xff1a; Model Based RL 1.1 通过环境分类 1.1.1 不理解环境 Model-Fr…

4.5 习题(王晓云 主编)

一、选择题1. 下面( ) 是错误的if 语句&#xff08;设int x,a,b;&#xff09;BA&#xff09;if (ab) x; B&#xff09;if (a<b) x;C&#xff09;if (a-b) x; D&#xff09;if (x ) x;2. 以下程序片段( )。Dvoid main ( ){int x0,y0,z0;if (xyz) printf(“***”);else printf…

RT-Thread SP使用教程

RT-Thread SPI 使用教程 实验环境使用的是正点原子的潘多拉开发板。 SPI从机设备使用的是BMP280温湿度大气压传感器。 使用RT-Thread Studio搭建基础功能。 1. 创建工程 使用RT-Thread Studio IDE创建芯片级的工程。创建完成后&#xff0c;可以直接编译下载进行测试。 2.…

JVM学习篇垃圾收集器ParNewCMS与底层三色标记算法详解

1. 垃圾收集算法 2. 分代收集理论 当前虚拟机的垃圾收集都采用分代收集算法&#xff0c;这种算法没有什么新的思想&#xff0c;只是根据对象存活周期的不同将内存分为几块。一般将java堆分为新生代和老年代&#xff0c;这样我们就可以根据各个年代的特点选择合适的垃圾收集算法…

因果推断7--深度因果模型综述(个人笔记)

目录 0摘要 1介绍 2预习 3治疗和指标 4深层因果模型的发展 4.1发展时间表 4.2模型分类 5典型的深层因果模型 6实验指南 6.1数据集 6.2code 6.3实验 7结论 参考 编码 1.自编码器(AE)&#xff1a; 2.去噪自编码器(DAE) 3.变分自编码器VAE 4.去耦变分自编码 文章…