[Vue3]computed原理
Computed原理
不管在是 Vue 2 还是在 Vue 3 中,对 computed 本身的实现原理基本都是一样的。当使用 computed 计算属性时,组件初始化会对每一个计算属性都创建对应的 watcher , 然后在第一次调用自己的 getter 方法时,收集计算属性依赖的所有 data,那么所依赖的 data 会收集这个订阅者同时会针对 computed 中的 key 添加属性描述符创建了独有的 get 方法,当调用计算属性的时候,这个 get 判断 dirty 是否为 true,为真则表示要要重新计算,反之直接返回 value。当依赖的 data 变化的时候回触发数据的 set 方法调用 update() 通知更新,此时会把 dirty 设置成 true,所以 computed 就会重新计算这个值,从而达到动态计算的目的。
理解computed原理其实对应着三个问题:
-
computed初始化流程
-
改变computed的依赖值是如何触发computed值改变的
-
computed值是如何做到缓存的
computed使用方式
第一种使用方式,接受一个 getter 函数,并根据 getter 的返回值返回一个不可变的响应式 ref 对象。
const count = ref(1)
const a = computed(() => count.value + 1)console.log(a.value) // 2a.value++ // 错误
第二种使用方式,接受一个具有 get 和 set 函数的对象,用来创建可写的 ref 对象。
const count = ref(1)
const a = computed({get: () => count.value + 1,set: val => {count.value = val - 1}
})a.value = 1
console.log(count.value) // 0
computed源码
当调用 computed 方法时,会根据两种调用方式做一下区分,同时调用类 ComputedRefImpl
function computed(getterOrOptions, ...) {let getter;let setter;const onlyGetter = isFunction(getterOrOptions);if (onlyGetter) {getter = getterOrOptions;setter = () => {console.warn('Write operation failed: computed value is readonly');};}else {getter = getterOrOptions.get;setter = getterOrOptions.set;}const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR);...return cRef;
}
ComputedRefImpl 类 :
class ComputedRefImpl {// 初始化constructor(getter, _setter, isReadonly, isSSR) {this._setter = _setter;this.dep = undefined;this.__v_isRef = true;this._dirty = true;this.effect = new ReactiveEffect(getter, () => {if (!this._dirty) {this._dirty = true;triggerRefValue(this);}});this.effect.computed = this;this.effect.active = this._cacheable = !isSSR;// 根据传入是否有setter函数来决定是否只读this["__v_isReadonly" /* IS_READONLY */] = isReadonly;}get value() {const self = toRaw(this);trackRefValue(self);if (self._dirty || !self._cacheable) {self._dirty = false;self._value = self.effect.run();}return self._value;}set value(newValue) {this._setter(newValue);}
}
初始化
ComputedRefImpl 类的第一块就是 computed 的初始化,主要做两件事情:
- 创建
effect对象,生成watcher监听函数并赋值给实例的effect属性。将当前getter当做监听函数,并附加调度器。 - 设置 computed ref 是否只是可读。设置是否可读的依据是:
onlyGetter||!setter
不过单单从构造方法来看其实和 computed 没有太大的关系,只是进行了初始化变量的操作,并创建了一个 ComputedRef 实例赋值给我们的调用。
声明一个 computed 时其实并不会执行 getter 方法,只有在读取 computed 值时才会执行它的 getter 方法,那么接下来要关注 ComputedRefImpl 的 getter 方法。
执行getter方法
第二部分就是 getter 方法的执行,getter 方法会在读取 computed 值的时候执行,而在 getter 方法中有一个叫 _dirty 的变量,它的意思是代表脏数据的开关,默认初始化时 _dirty 被设为 true ,在 getter 方法中表示开关打开,需要计算一遍 computed 的值,然后关闭开关,之后再获取 computed 的值时由于 _dirty 是 false 就不会重新计算。这就是 computed 缓存值的实现原理。
get value() {...if (self._dirty || !self._cacheable) {self._dirty = false;self._value = self.effect.run();}return self._value;
}
那么 computed 是怎么知道要重新计算值的呢?
computed 本身是依赖响应式属性的变化的,如果依赖的响应属性发生改变,会触发 effect 的 scheduler 函数执行。此方法就是 computed 内部依赖的状态变化时会执行的操作。所以最终的流程就是:computed 内部依赖的状态发生改变,执行对应的监听函数,这其中自然会执行 scheduler 里的操作。而在 scheduler 中将 _dirty 设为了 true 。
this.effect = new ReactiveEffect(getter, () => {// effect 的 scheduler 函数执行if (!this._dirty) {this._dirty = true;triggerRefValue(this);}
});
那么computed 是怎么知道内部依赖产生了变化呢?这是由于在我们第一次获取 computed 值(即执行 getter 方法) 的时候对内部依赖进行了访问,在那个时候就对其进行了依赖收集操作,所以 computed 能够知道内部依赖产生了变化。
注意:上面提到的「第一次获取 computed 值」这里是第一次get,而不是初始化 computed。
总结
总结来说,computed在第一次get的时候在内部收集了依赖,并将内部缓存开关设为了false,此后只有在依赖改变的时候,才会将内部缓存开关设为true,从而使computed的值发生改变。
相关文章:
[Vue3]computed原理
Computed原理 不管在是 Vue 2 还是在 Vue 3 中,对 computed 本身的实现原理基本都是一样的。当使用 computed 计算属性时,组件初始化会对每一个计算属性都创建对应的 watcher , 然后在第一次调用自己的 getter 方法时,收集计算属性依赖的所有…...
Vue工程化开发中各文件的作用
1.main.js文件 main.js文件的主要作用:导入App.vue,基于App.vue创建结构渲染index.html。...
【c++笔试强训】(第三十一篇)
目录 最⻓回⽂⼦序列(动态规划-区间dp) 题目解析 讲解算法原理 编写代码 添加字符(字符串) 题目解析 讲解算法原理 编写代码 最⻓回⽂⼦序列(动态规划-区间dp) 题目解析 1.题目链接:最…...
Go 1.19.4 HTTP编程-Day 20
1. HTTP协议 1.1 基本介绍 HTTP协议又称超文本传输协议,属于应用层协议,在传输层使用TCP协议。HTTP协议属是无状态的,对事务处理没有记忆能力,如果需要保存状态需要引用其他技术,如Cookie。HTTP协议属是无连接的&…...
MySQL 8.0 的主主复制(双向复制)
在 Windows Server 2022 Datacenter 上配置 MySQL 8.0 的主主复制(双向复制),步骤与 Linux 类似,但有一些特定的配置和路径需要注意。以下是详细的简化步骤: 1. 使用 root 用户登录 确保你以 root 用户登录到 MySQL …...
四、自然语言处理_03LSTM与GRU
0、前言 随着循环神经网络(RNN)在各种序列数据处理任务中被广泛应用,研究人员逐渐发现了其在处理长序列数据时会容易出现梯度消失(vanishing gradient)和梯度爆炸(exploding gradient)问题&…...
磁盘系列基础知识(一):硬盘;IDE;ATA;SATA;AHCI;SCSI;SAS
磁盘系列基础知识(一)硬盘 IDE ATA SATA AHCI SCSI SAS 硬盘厂家 西部数据Western Digital/WD. 希捷 SEAGATE、三星 SAMSUNG、东之 Toshiba、英特尔 Intel、金士顿 Kingston、闪迪 SanDisk、 英睿达 Crucial、浦科特 Plextor 硬盘类别 HDD (…...
taro小程序进入腾讯验证码
接入原因 昨天突然晚上有人刷我们公司的登录发送短信接口,紧急将小程序的验证码校验更新上去了 接下来就是我们的接入方法,其实很简单,不过有时候可能大家着急就没有仔细看文档,腾讯验证码文档微信小程序地址,注意这里…...
原子类相关
原子引用 JUC 并发包提供了: AtomicReferenceAtomicMarkableReferenceAtomicStampedReference AtomicReference 使用举例 public interface DecimalAccount {// 获取余额BigDecimal getBalance();// 取款void withdraw(BigDecimal amount);/*** 方法内会启动 10…...
RabbitMQ 客户端 连接、发送、接收处理消息
RabbitMQ 客户端 连接、发送、接收处理消息 一. RabbitMQ 的机制跟 Tcp、Udp、Http 这种还不太一样 RabbitMQ 服务,不是像其他服务器一样,负责逻辑处理,然后转发给客户端 而是所有客户端想要向 RabbitMQ服务发送消息, 第一步&a…...
Java Web 3 Axios Vue组件库
一 Ajax 1 同步 异步 2 原生Ajax 比较繁琐 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Documen…...
双目相机的标定,视差图,深度图,点云生成思路与实现。
该文档记录从双目相机标定到点云生成的所有过程,同时会附上代码。 代码直接能跑。https://github.com/stu-yzZ/stereoCamera 目录 大致思路如下: 一、相机标定 1、相机参数介绍 2、单目相机标定 3、双目相机标定 二、图片畸变矫正 三、极线矫正…...
【H2O2|全栈】MySQL的基本操作(三)
目录 前言 开篇语 准备工作 案例准备 多表查询 笛卡尔积 等值连接 外连接 内连接 自连接 子查询 存在和所有 含于 分页查询 建表语句 结束语 前言 开篇语 本篇继续讲解MySQL的一些基础的操作——数据字段的查询中的多表查询和分页查询,与单表查询…...
2、C++命名空间
命名空间 命名空间是一种用来避免命名冲突的机制; 原理是将一个全局的作用域分成一个个命名空间,每个命名空间是个单独的作用域,从而有效避免命名冲突。 注意:命名空间定义在全局 命名空间定义格式 使用: …...
Elemenu-UI时间日期单个组件,限制当前日期之后的时间
element的时间日期组件, type"datetime" ,当你设置了:picker-options"pickerOptions"之后 pickerOptions: { disabledDate(time) { return time.getTime() > Date.now(); }, }, 会发现,他只会限制日期,但不…...
flutter修改状态栏学习
在flutter中如何动态更改状态栏的颜色和风格。 前置知识点学习 AnnotatedRegion AnnotatedRegion 是 Flutter 中的一个小部件,用于在特定区域中提供元数据(metadata)以影响某些系统级的行为或外观。它通常用于改变系统 UI 的外观ÿ…...
解决Unity编辑器Inspector视图中文注释乱码
1.问题介绍 新创建一个脚本,用VS打开编辑,增加一行中文注释保存,在Unity中找到该脚本并选中,Inspector视图中预览的显示内容,该中文注释显示为乱码,如下图所示: 2.图示解决步骤 按上述步骤操作…...
关于csgo的游戏作弊与封禁
关于csgo的游戏作弊与封禁 一.关于作弊 什么叫作弊? 1.换肤,换库存 2.各种参(回溯,自瞄,透视,急停,连跳,假身,子弹跟踪等) 3.某一部分更改游戏内存&…...
严格单元测试造就安全软件
在信息技术迅速发展的今天,软件在各个行业中扮演着至关重要的角色,尤其是在汽车行业,其中软件的可靠性和安全性直接影响到人们的生命安全。软件缺陷所带来的潜在风险不容小觑,尤其在涉及到自动驾驶和车辆控制等关键系统时…...
ubuntu 根分区逻辑卷扩容
1、虚拟机关机通过管理界面给磁盘扩容。 rootcurtis:/home/curtis/git_code# pvdisplay--- Physical volume ---PV Name /dev/vda3VG Name ubuntu-vgPV Size <239.00 GiB / not usable 0Allocatable yes (but full)PE…...
OpenClaw人人养虾:LiteLLM 统一网关
LiteLLM 是一个开源的 LLM API 统一网关(Unified Gateway),支持 100 模型提供商,提供统一的 OpenAI 兼容 API 格式。 安装 LiteLLM pip 安装 pip install litellm[proxy] Docker 安装 docker run -p 4000:4000 \-e OPENAI_AP…...
5分钟搞定Windows风扇智能控制:告别噪音烦恼,打造极致静音电脑系统
5分钟搞定Windows风扇智能控制:告别噪音烦恼,打造极致静音电脑系统 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode…...
OpenSpeedy游戏变速工具实战指南:打破帧率限制的完整攻略
OpenSpeedy游戏变速工具实战指南:打破帧率限制的完整攻略 【免费下载链接】OpenSpeedy 🎮 An open-source game speed modifier. 项目地址: https://gitcode.com/gh_mirrors/op/OpenSpeedy OpenSpeedy是一款开源免费的游戏变速工具,能…...
OpenClaw技能开发案例:为千问3.5-9B添加日历管理功能
OpenClaw技能开发案例:为千问3.5-9B添加日历管理功能 1. 为什么需要自定义日历管理技能 去年我接手了一个私人项目,需要定期跟踪十几个线上活动的排期。最初尝试用Python脚本Google Calendar API管理,但每次修改都要手动调整代码参数。后来…...
Multisim新手必看:用差分放大电路课设,手把手教你搞定仿真与波形分析
Multisim新手必看:用差分放大电路课设,手把手教你搞定仿真与波形分析 第一次打开Multisim时,满屏的元器件和复杂的参数设置确实容易让人望而生畏。记得我大三做模电课设时,光是找齐差分放大电路需要的元件就花了半小时,…...
AI辅助开发:用自然语言描述需求,让快马平台自动生成精准的Copaw自动化脚本
AI辅助开发:用自然语言描述需求,让快马平台自动生成精准的Copaw自动化脚本 最近在做一个自动化测试项目,需要大量使用Copaw框架来模拟用户操作。作为一个刚接触Copaw的新手,最头疼的就是要花大量时间研究各种API和页面元素定位方…...
STM32F103C8T6+TJA1042+UTA0403:手把手教你搭建CAN通讯测试环境(附完整接线图)
STM32F103C8T6TJA1042UTA0403:从零构建工业级CAN总线测试平台 第一次接触CAN总线的工程师往往会被物理层连接的各种细节困扰——为什么收发器需要独立供电?STB引脚悬空会导致什么后果?如何避免共模干扰?本文将用实验室级精度拆解S…...
终极Windows驱动管理指南:如何用DriverStore Explorer快速释放30GB磁盘空间
终极Windows驱动管理指南:如何用DriverStore Explorer快速释放30GB磁盘空间 【免费下载链接】DriverStoreExplorer Driver Store Explorer 项目地址: https://gitcode.com/gh_mirrors/dr/DriverStoreExplorer DriverStore Explorer(简称RAPR&…...
HagiCode Soul 平台技术解析:从需求萌发到独立平台的演进之路
先回顾:三次握手(建立连接)核心流程(实际版) 为了让挥手流程衔接更顺畅,咱们先快速回顾三次握手的实际核心,避免上下文脱节: 第一步(客户端→服务器)…...
PyTorch 2.8镜像作品集:基于OpenCV+Torch的实时手势识别视频演示
PyTorch 2.8镜像作品集:基于OpenCVTorch的实时手势识别视频演示 1. 镜像环境与能力概览 PyTorch 2.8深度学习镜像是一个经过深度优化的专业级开发环境,专为现代AI应用设计。这个环境最吸引人的特点是它已经预装了所有必要的工具和库,让你可…...
