Vue3源码reactivity响应式篇之EffectScope

概述

EffectScope是Vue3中一个响应式系统的辅助类,用于管理副作用(effect)的作用域。它可以帮助我们更好地组织和管理多个effect,便于一起停止或暂停以及恢复,避免了全局状态的污染和管理的复杂性。

每一个vue组件的实例上都会挂载一个EffectScope的实例scope,该挂载动作会在createComponentInstance中进行。在组件被激活挂载时,会调用scope.on()方法,将当前作用域设置为活动作用域;而在组件被卸载或者销毁时,会调用scope.stop()方法。

源码解析

let activeEffectScope;class EffectScope {constructor(detached = false) {this.detached = detached; // 表示该作用域是否独立(不嵌套在父作用域中)this._active = true; //表示作用域是否激活this._on = 0; // 一个计数器,用于记录当前作用域被开启的次数(通过on方法)this.effects = []; // 存储属于该作用域的effectthis.cleanups = []; // 存储清理函数,当作用域停止时会执行这些清理函数this._isPaused = false; // 表示作用域是否被暂停this.parent = undefined; //指向父作用域this.scopes = undefined; //存储嵌套的子作用域this.index = undefined; // 在父作用域的scopes数组中的索引this.prevScope = undefined; // 在调用 on 方法时,用于保存当前的activeEffectScope,以便在off时恢复,上一个作用域(用于作用域链)this.parent = activeEffectScope; //将父作用域指向激活的作用域if (!detached && activeEffectScope) {// 若该作用域不独立且当前存在激活的作用域,则将该作用域存放到激活作用域(父作用域)的子作用域的末尾,并设置该作用域的索引this.index = (activeEffectScope.scopes || (activeEffectScope.scopes = [])).push(this) - 1;}}// 暂停作用域pause() {if (this._active) {this._isPaused = true;let i, l;if (this.scopes) {for (i = 0, l = this.scopes.length; i < l; i++) {this.scopes[i].pause();}}for (i = 0, l = this.effects.length; i < l; i++) {this.effects[i].pause();}}}// 恢复作用域resume() {if (this._active) {if (this._isPaused) {this._isPaused = false;let i, l;if (this.scopes) {for (i = 0, l = this.scopes.length; i < l; i++) {this.scopes[i].resume();}}for (i = 0, l = this.effects.length; i < l; i++) {this.effects[i].resume();}}}}// 在作用域内运行函数run(fn) {if (this._active) {const currentEffectScope = activeEffectScope;try {activeEffectScope = this;return fn();} finally {activeEffectScope = currentEffectScope;}}}// 开启作用域on() {if (++this._on === 1) {this.prevScope = activeEffectScope;activeEffectScope = this;}}// 关闭作用域off() {if (this._on > 0 && --this._on === 0) {activeEffectScope = this.prevScope;this.prevScope = void 0;}}// 停止作用域stop(fromParent) {if (this._active) {this._active = false;let i, l;for (i = 0, l = this.effects.length; i < l; i++) {this.effects[i].stop();}this.effects.length = 0;for (i = 0, l = this.cleanups.length; i < l; i++) {this.cleanups[i]();}this.cleanups.length = 0;if (this.scopes) {for (i = 0, l = this.scopes.length; i < l; i++) {this.scopes[i].stop(true);}this.scopes.length = 0;}if (!this.detached && this.parent && !fromParent) {const last = this.parent.scopes.pop();if (last && last !== this) {this.parent.scopes[this.index] = last;last.index = this.index;}}this.parent = void 0;}}
}
核心方法

核心方法主要分为三类:作用域控制(pause/resume/stop)、作用域运行(run)和作用域激活(on/off)

作用域控制
  • pause

pause方法就是用于暂停作用域及其所有子作用域和副作用。先是判断作用域是否处于激活状态,若是激活状态,则修改作用域的暂停状态this._isPaused,改为true,然后遍历子作用域和副作用数组,调用其stop方法实现暂停。

  • resume

resume方法用于暂停状态的作用域及其所有子作用域和副作用。和pause方法是相反的操作,会修改this.isPausedfalse,遍历调用所有子作用域和副作用的resume方法。

  • stop

stop方法用于停止作用域:清理所有副作用和子作用域,并且从父作用域中移除自身。

stop方法会停止所有effect,执行所有cleanups,并递归停止所有子作用域。如果该作用域不是独立的且由副作用域,并且不是由副作用域触发的停止,则从副作用域的scopes数组中移除自己,并调整数组。

作用域运行
  • run

run方法用于在该作用域内运行函数,这样函数内创建的effect会自动注册到该作用域中。主要就是将该作用域切换为激活作用域,然后执行fn,最后恢复激活作用域为之前的。

作用域激活
  • on

on方法用于激活作用域,就是增加计数器,若计数器增加后等于 1,则将该作用域作为激活作用域。

  • off

off方法和on方法相对,用于关闭作用域,减少计数器,若计数器大于 0,且减少后等于0,则恢复激活作用域为前值。

通过on/off方法,可以临时切换当前激活的作用域,这样可以实现在onoff切换之间创建effect会注册到该作用域中。

辅助方法

EffectScope类相关的三个辅助方法:effectScopegetCurrentScopeonScopeDispose

  • effectScope

effectScope方法就是返回EffectScope的实例对象。

function effectScope(detached) {return new EffectScope(detached);
}
  • getCurrentScope

getCurrentScope方法用于获取当前活跃(激活)的作用域

function getCurrentScope() {return activeEffectScope;
}
  • onScopeDispose

onScopeDispose方法会判断若当前作用域存在,则将函数fn注入到作用域的清理数组cleanups中。

function onScopeDispose(fn, failSilently = false) {if (activeEffectScope) {activeEffectScope.cleanups.push(fn);}
}

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

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

相关文章

MySQL 日志全解析:Binlog/Redo/Undo 等 5 类关键日志的配置、作用与最佳实践

1 二进制日志&#xff08;Binlog&#xff09;&#xff1a;配置与核心作用 Binlog 是 MySQL 中跨存储引擎的核心日志&#xff0c;记录所有数据修改操作&#xff0c;主要用于主从复制、数据备份恢复与跨库迁移。 1.1 Binlog 核心操作 开启 Binlog 若需开启 Binlog&#xff0c;需在…

springboot 之 HTML与图片生成 (2)

前言 之前写了一篇html转图片的 文章&#xff0c;使用中文时会出现乱码情况&#xff0c;后来又从网上找了下信息&#xff0c;这篇主要介绍下另一个转换库。 依赖 <!-- 用于将html转图片--><dependency><groupId>gui.ava</groupId><artifactId>…

计算机组成原理:计算机的分类

&#x1f4cc;目录&#x1f5a5;️ 计算机组成原理&#xff1a;计算机的分类——从架构到应用的全景梳理一、按处理数据类型分类&#xff1a;从“数字”到“混合”的演进&#xff08;一&#xff09;数字计算机&#xff1a;离散数据的“精准管家”1. 核心原理2. 关键优势3. 典型…

数据结构——单向循环链表代码(补充)

在此前的文章中&#xff08;链接如下&#xff09;&#xff0c;只有单向链表的代码&#xff0c;接下来我们来写单向循环链表&#xff0c;并用其实现一个简单的学生信息链表https://blog.csdn.net/2301_80406299/article/details/151157051?spm1011.2415.3001.10575&sharefr…

【Python自动化】 21.2 Pandas 读取 Excel 时的 dtype 参数完全指南

一、dtype 参数概述 dtype 参数用于指定列的数据类型&#xff0c;在读取 Excel 时非常重要&#xff0c;可以&#xff1a; 提高内存效率避免自动类型推断错误确保数据一致性提升读取性能 二、基本用法 1. 基础语法 import pandas as pd# 指定列数据类型 df pd.read_excel(data.…

gtest全局套件的测试使用

gtest全局套件的测试使用 #include <iostream> #include "gtest/gtest.h" #include <unordered_map>class MyEnvironment: public testing::Environment {public:virtual void SetUp() override{std::cout<<"单元测试前的环境初始化&#xff…

【系统分析师】第7章-基础知识:软件工程(核心总结)

更多内容请见: 备考系统分析师-专栏介绍和目录 文章目录 一、软件工程的基本概念 1.1 定义与意义 1.2 软件工程的基本原则 1.3 核心定义与边界 1.4 四大核心原则 1.5 三大核心目标 二、软件生命周期 2.1 定义与阶段划分 2.2 软件生命周期模型 三、软件开发方法 3.1 结构化方法…

量化基金从小白到大师 - 金融数据获取大全:从免费API到Tick级数据实战指南

量化基金从小白到大师 - 金融数据获取大全&#xff1a;从免费API到Tick级数据实战指南 各位&#xff0c;今天咱们要啃一块硬骨头——金融数据获取。别看这话题基础&#xff0c;它可是整个量化大厦的地基&#xff0c;地基不稳&#xff0c;再牛的策略都得塌房。我见过太多人&…

构建一个“会思考”的房地产数据获取脚本

—— 跨界思维&#xff1a;从认知自适应到房源信息监测 一、认知科学视角&#xff1a;什么是“会思考” 在心理学与认知科学中&#xff0c;所谓“会思考”&#xff0c;并不是指抽象的哲学推理&#xff0c;而是指个体能在复杂环境中不断调整行动策略。 比如&#xff0c;出行时如…

JavaScript的库简介

JavaScript拥有丰富的库生态系统,类似于Python的requests、numpy或C++的Boost。这些库分为两大类:前端库(如React、Vue)和后端/工具库(如Lodash、Axios)。以下是几个核心库的介绍与用法示例。 常用JavaScript库分类 前端UI库 React:Facebook开发的组件化库,用于构建用…

【无GGuF版本】如何在Colab下T4运行gpt-oss 20B

OpenAI发布了gpt-oss 120B和20B版本。这两个模型均采用Apache 2.0许可证。 特别说明的是&#xff0c;gpt-oss-20b专为低延迟及本地化/专业化场景设计&#xff08;210亿总参数&#xff0c;36亿活跃参数&#xff09;。 由于模型采用原生MXFP4量化训练&#xff0c;使得20B版本即…

LeetCode - LCR 179. 查找总价格为目标值的两个商品

题目 https://leetcode.cn/problems/he-wei-sde-liang-ge-shu-zi-lcof/submissions/660817798/ 思路 解法1是暴力解法&#xff0c;从第一个开始和后面的相加 暴力枚举慢就慢在&#xff0c;这个递增数组是排序好的数组&#xff0c;已经是有序的&#xff0c;暴力解法没有利用这…

UI自动化测试Python + Selenium + WinAppDriver( Windows 桌面应用)落地(一)环境搭建

最近公司要求为Windows 端桌面应用进行UI自动化测试,之前都是针对web端进行的UI自动化测试或者在早期使用的是QTP(Quick Test Professional)做PC端的UI自动化测试,而基于"经费"紧张,优先选择开源的工具,所以选择了selenium + WinAppDriver来实现。 首先,整理…

基于OpenCV的银行卡号识别系统:从原理到实现

引言在现代金融科技应用中&#xff0c;银行卡号的自动识别是一项重要技术。本文将详细介绍如何使用Python和OpenCV库构建一个完整的银行卡号识别系统。该系统能够从银行卡图像中提取卡号信息&#xff0c;并根据卡号首数字判断银行卡类型。技术栈​OpenCV: 计算机视觉库&#xf…

概率论第三讲——多维随机变量及其分布

文章目录考纲n维随机变量及其分布函数联合分布函数边缘分布函数二维离散型随机变量的概率分布、边缘分布和条件分布二维连续型随机变量的概率密度、边缘概率密度和条件概率密度常见的二位分布二维均匀分布二维正态分布随机变量的相互独立性概念相互独立的充要条件相互独立的性质…

纯软件实现电脑屏幕录制/存储到硬盘录像机/onvif模拟器/onvif虚拟监控/绿色版双击开箱即用

一、前言说明 在银行、超市、考试中心、工控系统、网课教学、居家办公等场景中&#xff0c;传统监控摄像头难以清晰录制电脑屏幕内容&#xff0c;导致关键操作无法有效追溯。为解决这一难题&#xff0c;我们推出了一套纯软件实现的电子屏幕监控方案&#xff0c;彻底取代依赖硬…

【算法--链表】86.分割链表--通俗讲解

一、题目是啥?一句话说清 给你一个链表和一个值 x,把链表分成两部分:所有小于 x 的节点都放在大于或等于 x 的节点之前,并且保持节点原来的相对顺序。 示例: 输入:head = [1,4,3,2,5,2], x = 3 输出:[1,2,2,4,3,5](所有小于3的节点1、2、2都在大于等于3的节点4、3、5…

707, 设计链表, LinkedList, 单链表, Dummy Head, C++

目录 题意速览解题思路与设计要点C 代码实现&#xff08;单链表 虚拟头结点&#xff09;时间复杂度与空间复杂度常见坑位与边界用例对比&#xff1a;双链表如何优化单元测试样例&#xff08;可直接粘贴运行&#xff09;总结 题意速览 设计一个支持如下操作的链表&#xff1a…

NAS自建笔记服务leanote2

leanote2(GitHub - wiselike/leanote2: leanote2, 适用于NAS自建的笔记服务) 是一个开源的在线笔记应用程序&#xff0c;继承自原 leanote 项目。向原 leanote 的开发者表示深深的感谢与尊重&#xff0c;正是他们的辛勤付出奠定了这个优秀的笔记平台的基础。 但由于 leanote 项…

模型剪枝----ResNet18剪枝实战

剪枝 模型剪枝&#xff08;Model Pruning&#xff09; 是一种 模型压缩&#xff08;Model Compression&#xff09; 技术&#xff0c;主要思想是&#xff1a; 深度神经网络里有很多 冗余参数&#xff08;对预测结果贡献很小&#xff09;。 通过去掉这些冗余连接/通道/卷积核&am…