当前位置: 首页 > news >正文

[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 方法,那么接下来要关注 ComputedRefImplgetter 方法。

执行getter方法

第二部分就是 getter 方法的执行,getter 方法会在读取 computed 值的时候执行,而在 getter 方法中有一个叫 _dirty 的变量,它的意思是代表脏数据的开关,默认初始化时 _dirty 被设为 true ,在 getter 方法中表示开关打开,需要计算一遍 computed 的值,然后关闭开关,之后再获取 computed 的值时由于 _dirtyfalse 就不会重新计算。这就是 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…...

双目相机的标定,视差图,深度图,点云生成思路与实现。

该文档记录从双目相机标定到点云生成的所有过程&#xff0c;同时会附上代码。 代码直接能跑。https://github.com/stu-yzZ/stereoCamera 目录 大致思路如下&#xff1a; 一、相机标定 1、相机参数介绍 2、单目相机标定 3、双目相机标定 二、图片畸变矫正 三、极线矫正…...

【H2O2|全栈】MySQL的基本操作(三)

目录 前言 开篇语 准备工作 案例准备 多表查询 笛卡尔积 等值连接 外连接 内连接 自连接 子查询 存在和所有 含于 分页查询 建表语句 结束语 前言 开篇语 本篇继续讲解MySQL的一些基础的操作——数据字段的查询中的多表查询和分页查询&#xff0c;与单表查询…...

2、C++命名空间

命名空间 命名空间是一种用来避免命名冲突的机制; 原理是将一个全局的作用域分成一个个命名空间&#xff0c;每个命名空间是个单独的作用域,从而有效避免命名冲突。 注意&#xff1a;命名空间定义在全局 命名空间定义格式 使用&#xff1a; …...

Elemenu-UI时间日期单个组件,限制当前日期之后的时间

element的时间日期组件&#xff0c; type"datetime" &#xff0c;当你设置了:picker-options"pickerOptions"之后 pickerOptions: { disabledDate(time) { return time.getTime() > Date.now(); }, }, 会发现&#xff0c;他只会限制日期&#xff0c;但不…...

flutter修改状态栏学习

在flutter中如何动态更改状态栏的颜色和风格。 前置知识点学习 AnnotatedRegion AnnotatedRegion 是 Flutter 中的一个小部件&#xff0c;用于在特定区域中提供元数据&#xff08;metadata&#xff09;以影响某些系统级的行为或外观。它通常用于改变系统 UI 的外观&#xff…...

解决Unity编辑器Inspector视图中文注释乱码

1.问题介绍 新创建一个脚本&#xff0c;用VS打开编辑&#xff0c;增加一行中文注释保存&#xff0c;在Unity中找到该脚本并选中&#xff0c;Inspector视图中预览的显示内容&#xff0c;该中文注释显示为乱码&#xff0c;如下图所示&#xff1a; 2.图示解决步骤 按上述步骤操作…...

关于csgo的游戏作弊与封禁

关于csgo的游戏作弊与封禁 一.关于作弊 什么叫作弊&#xff1f; 1.换肤&#xff0c;换库存 2.各种参&#xff08;回溯&#xff0c;自瞄&#xff0c;透视&#xff0c;急停&#xff0c;连跳&#xff0c;假身&#xff0c;子弹跟踪等&#xff09; 3.某一部分更改游戏内存&…...

严格单元测试造就安全软件

在信息技术迅速发展的今天&#xff0c;软件在各个行业中扮演着至关重要的角色&#xff0c;尤其是在汽车行业&#xff0c;其中软件的可靠性和安全性直接影响到人们的生命安全。软件缺陷所带来的潜在风险不容小觑&#xff0c;尤其在涉及到自动驾驶和车辆控制等关键系统时&#xf…...

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…...

基于RK3588S与鸿蒙系统的SOM核心板:高性能嵌入式AIoT开发实战

1. 项目概述&#xff1a;一颗“全能芯”的鸿蒙新载体最近在嵌入式圈子里&#xff0c;一个消息挺让人兴奋的&#xff1a;触觉智能基于瑞芯微RK3588S这颗“明星”SoC打造的SOM3588S核心板&#xff0c;正式支持鸿蒙系统并上市了。这不仅仅是又多了一块高性能的核心板&#xff0c;它…...

聚合物半导体薄膜:柔性电子皮肤如何实现无感健康监测

1. 项目概述&#xff1a;从“硬核”到“柔韧”的健康监测革命如果你还在用那些又厚又硬、贴着皮肤半天就发痒发红的老式健康监测电极&#xff0c;是时候了解一下这个正在改变游戏规则的新玩意儿了——聚合物半导体薄膜。这可不是什么实验室里的遥远概念&#xff0c;它正从顶尖期…...

DayZCommunityOfflineMode:构建专属末日世界的完整解决方案

DayZCommunityOfflineMode&#xff1a;构建专属末日世界的完整解决方案 【免费下载链接】DayZCommunityOfflineMode A community made offline mod for DayZ Standalone 项目地址: https://gitcode.com/gh_mirrors/da/DayZCommunityOfflineMode DayZCommunityOfflineMod…...

按键精灵PC版和手机版到底怎么选?一篇讲清四大版本区别与核心开发流程

按键精灵四大版本深度解析&#xff1a;从需求匹配到高效开发的完整指南 在自动化工具领域&#xff0c;按键精灵凭借其跨平台支持和易用性&#xff0c;成为许多用户的首选。但面对官网提供的四个不同版本——电脑版、手机助手、安卓版和IOS版&#xff0c;不少新手用户会感到困惑…...

从零到专业:ComfyUI中文工作流全解析与技术实践

从零到专业&#xff1a;ComfyUI中文工作流全解析与技术实践 【免费下载链接】ComfyUI-Workflows-ZHO 我的 ComfyUI 工作流合集 | My ComfyUI workflows collection 项目地址: https://gitcode.com/GitHub_Trending/co/ComfyUI-Workflows-ZHO 在AI图像生成领域&#xff0…...

别再只写assign了!用三种Verilog建模风格重构你的三人表决器(行为级/数据流/门级)

别再只写assign了&#xff01;用三种Verilog建模风格重构你的三人表决器 三人表决器是数字电路设计中的经典案例&#xff0c;它能直观展示不同抽象层次的Verilog建模风格如何影响代码质量与硬件实现。很多工程师习惯性地使用assign语句完成所有设计&#xff0c;却忽略了Verilo…...

终极指南:5分钟为WinForms应用注入Material Design现代化界面

终极指南&#xff1a;5分钟为WinForms应用注入Material Design现代化界面 【免费下载链接】MaterialSkin Theming .NET WinForms, C# or VB.Net, to Googles Material Design Principles. 项目地址: https://gitcode.com/gh_mirrors/mat/MaterialSkin MaterialSkin 2是一…...

终极AMD Ryzen调试指南:简单三步掌握硬件性能调优

终极AMD Ryzen调试指南&#xff1a;简单三步掌握硬件性能调优 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: https://gitcod…...

RimWorld模组管理终极指南:3步掌握RimSort智能排序,告别游戏崩溃烦恼

RimWorld模组管理终极指南&#xff1a;3步掌握RimSort智能排序&#xff0c;告别游戏崩溃烦恼 【免费下载链接】RimSort RimSort is an open source mod manager for the video game RimWorld. There is support for Linux, Mac, and Windows, built from the ground up to be a…...

Keil MDK 项目迁移避坑指南:当你的旧工程遇到‘Default Compiler Version 5 is not available’

Keil MDK项目迁移实战&#xff1a;编译器版本冲突的工程级解决方案 当你从同事手中接过一个历史遗留的Keil MDK项目&#xff0c;或从版本控制系统拉取多年前的嵌入式工程时&#xff0c;最令人头疼的莫过于打开工程后迎面而来的编译器报错。其中"Default Compiler Version …...