vue源码解析—— watch/computed的实现逻辑和区别

watchcomputed 是 Vue 中的两个重要的响应式属性,它们在实现机制和使用上存在一些区别。

  • watch:用于监听数据的变化,并在数据变化时执行回调函数。可以使用 deep 配置项来开启深度监听,监听数据的子属性变化。可以使用 immediate 配置项来立即执行回调函数。
  • computed:用于计算数据,并在数据变化时重新计算数据。可以使用 get 函数来计算数据,并在依赖的数据变化时重新计算数据。可以使用 set 函数来设置数据,并在数据变化时执行回调函数。

  Vue 2 中,使用 Object.defineProperty 来实现数据响应式,并且在数据变化时通过 getter 函数来依赖收集和发布订阅。在 Vue 3 中,使用 Proxy 来实现数据响应式,并且在数据变化时通过 get 函数来依赖收集和发布订阅。这也导致了在源码实现上vue2和vue3的不同。

watch 和 computed

watch用法

watch 用于监听数据的变化,当数据变化时,可以执行相应的操作。它可以用在数据的深层次监听异步操作、或者需要在数据变化后执行某个操作的场景。

new Vue({data: {message: 'hello'},watch: {message(newVal, oldVal) {console.log('message changed:', newVal, oldVal)}}
})

在上面的例子中,我们监听了 message 数据的变化,当 message 数据变化时,就会执行 console.log 函数。 

watch 还有一些高级用法,比如监听对象的变化,可以使用 deep 选项,如下: 

new Vue({data: {user: {name: 'John',age: 27}},watch: {user: {handler(newVal, oldVal) {console.log('user changed:', newVal, oldVal)},deep: true}}
})

computed用法

computed 用于计算数据,它可以基于数据的变化,动态地计算出新的数据。computed 的值会被缓存,只有当它依赖的数据发生变化时,才会重新计算

computed 的基本用法如下:

new Vue({data: {message: 'hello',reversedMessage: ''},computed: {reversedMessage() {return this.message.split('').reverse().join('')}}
})

在上面的例子中,我们定义了一个 reversedMessage 计算属性,它会动态地计算出 message 的反转字符串。当 message 变化时,reversedMessage 也会随之变化。

computed 还有一些高级用法,比如可以使用 getset 函数来实现双向数据绑定,如下:

new Vue({data: {message: 'hello'},computed: {fullName: {get() {return this.firstName + ' ' + this.lastName},set(value) {const names = value.split(' ')this.firstName = names[0]this.lastName = names[names.length - 1]}}}
})

watch和computed的区别、使用场景

watchcomputed 都可以用来监听数据的变化,但它们的用途和实现方式有所不同。

  • watch 是一个监听器,它可以监听数据的变化,并执行相应的操作。watch 可以用在数据的深层次监听异步操作、或者需要在数据变化后执行某个操作的场景。
  • computed 是一个计算属性,它可以基于数据的变化,动态地计算出新的数据。computed 的值会被缓存,只有当它依赖的数据发生变化时,才会重新计算。computed 可以用在需要对数据进行计算的场景,比如需要对数据进行过滤、排序、或者格式化的场景。computed不支持异步逻辑。

总的来说,watch 更适用于需要执行某个操作的场景,而 computed 更适用于需要对数据进行计算的场景。

面试官问:computed里可以进行异步操作吗?

在Vue中,computed属性默认是同步的,不支持直接进行异步操作。如果需要在computed中进行异步操作,可以使用async/await结合一个异步函数来实现。但是需要注意的是,computed属性应该是一个同步的计算属性,而不应该依赖于异步操作的结果。异步操作应该放在methods中进行处理,或者使用watch监听数据的变化。这样可以确保computed属性的计算是同步的,避免出现意外的行为。

 watch源码解析

vue2

Vue 2 可以实现在监视属性的值发生变化时,触发对应的回调函数,并在回调函数中执行相应的操作。主要通过这两个方法 initWatch 和createWatcher实现。

initWatch函数遍历 watch 对象的所有属性,如果 handler 是一个数组,则遍历数组中的每个元素,并为每个元素创建一个监视器,如果 handler 是一个函数或一个纯对象,则直接创建一个监视器。createWatcher 函数用于创建一个监视器,createWatcher 函数最终返回 vm.$watch 函数的执行结果,即一个监视器对象。

 $watch方法本质上创建一个watcher,监听数据变化,数据变化后触发回调

 

vue3

watch 函数做了哪些事情:

1.watch 函数会在内部创建一个 Watcher 对象,并将其添加到当前组件的 watcher 队列中。当响应式数据变化时,会触发 Watcher 对象的更新函数,执行回调函数 cb。 

watch 函数接收三个参数:

source可以是一个响应式数据对象,也可以是一个 getter 函数,用于获取需要监听的数据。

cb回调函数,在数据变化时执行,可以接收三个参数:newValoldValonInvalidate

options可选参数,用于配置监听器函数的执行时机和调度方式,包括:

  • deep:是否开启深度监听。
  • immediate:是否立即执行回调函数。
  • flush:控制回调函数的调度执行时机,可以选择在同步或异步更新后执行。
  • onTrack:在监听器函数执行前调用。
  • onTrigger:在监听器函数执行后调用。

Watcher 对象的doWatch函数会执行以下步骤:

Watcher 对象的 doWatch 函数中,会创建一个 effect 函数,并将其与 scheduler 函数关联起来。当响应式数据变化时,会触发 effect 函数,执行 scheduler 函数,从而执行 watch 函数中定义的回调函数 cb

如果 getter 函数执行完成后,需要取消监听,可以调用 watch 函数返回的 StopWatch 对象的 stop 方法,从当前组件的 watcher 队列中移除 Watcher 对象。

可以看下job或SchedulerJob做了什么

执行 scheduler 函数,从而执行 watch 函数中定义的回调函数 cb,并在需要的情况下,更新新值和旧值的值,并执行 onInvalidate 函数。

在watch方法里提供了onCleanup方法,可以清除上一次的异步操作结果 

computed源码解析

computed的实现原理在面试中经常被问到,如果你只知道维护了一个dirty属性是远远不够的。computed为什么可以是一个属性,依赖的项的变化后,怎么通知computed属性的更改,甚至触发模板的渲染呢?这些都要去源码中获得答案。

vue2

vue2中源码地址:vue-main\src\core\instance\state.ts

 vue2源码整体思想如下:

  1. 计算属性会创建一个计算属性watcher,这个watcher{lazy:true}不会立刻执行
  2. 通过Object.defineProperty将计算属性定义到实例上
  3. 当用户取值时会触发getter,拿到计算属性对应的watcher,看dirty是否为true,如果为true则求值。
  4. 让计算属性watcher中依赖的属性收集最外层的渲染watcher,可以做到依赖的属性变化了,触发计算属性更新。
  5. 如果依赖的属性没有变化,采用缓存

 1.计算属性会创建一个计算属性watcher,这个watcher{lazy:true}不会立刻执行

watcher 的主要作用是:

  • 依赖收集:在 watcher 创建时,会将依赖的数据添加到 watcherdep 属性中,当依赖的数据变化时,会通知 watcher 执行回调函数。
  • 发布订阅:在 watcher 创建时,会将 watcher 添加到 depsubs 属性中,当依赖的数据变化时,会通知 dep 执行 notify 函数,从而执行 watcher 的回调函数。

 2.通过Object.defineProperty将方法定义为属性并绑定到实例上,这也是为什么计算属性是个方法却能得到属性

3.computed的核心逻辑:当用户取值时会触发getter,拿到计算属性对应的watcher,看dirty是否为true,如果为true则求值。

并且让计算属性watcher中依赖的属性收集最外层的渲染watcher,可以做到依赖的属性变化了,触发计算属性更新。如果依赖的属性没有变化,采用缓存

vue3

vue3的核心逻辑也是维护一个dirty属性;只不过增加了dirty级别,对dirty进行了分类

与vue2不同的是,vue3依赖收集不依赖watcher,而是改成了effect。

Vue 3 中的 computed 是通过 effect 函数和 computed 函数实现的。当定义一个 computed 计算属性时,Vue 3 会使用 effect 函数来创建一个响应式的计算属性对象,并在计算属性的 getter 函数中访问其他响应式数据。这样,计算属性就建立了与依赖数据的关联,当依赖数据变化时,计算属性会重新计算并返回新的值。

  1. effect 函数effect 函数是 Vue 3 中用于创建响应式副作用的函数。它接收一个函数作为参数,并在函数内部访问响应式数据时建立数据与副作用函数之间的依赖关系。当响应式数据发生变化时,effect 函数会重新运行副作用函数,从而触发更新。

  2. computed 函数computed 函数用于创建计算属性。在 Vue 3 中,computed 函数接收一个 getter 函数作为参数,该 getter 函数内部访问其他响应式数据,并返回一个计算值。computed 函数会使用 effect 函数来创建一个响应式的计算属性,当依赖的响应式数据发生变化时,计算属性会重新计算并返回新的值。

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

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

相关文章

基于51单片机和MAX1898的智能手机充电器设计

**单片机设计介绍,基于51单片机和MAX1898的智能手机充电器设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于51单片机和MAX1898的智能手机充电器设计概要 一、引言 随着智能手机的普及,其电池续航…

网络安全接入认证-802.1X接入说明

介绍 802.1X是一个网络访问控制协议,它可以通过认证和授权来控制网络访问。它的基本原理是在网络交换机和认证服务器之间建立一个安全的通道,并要求客户端提供身份验证凭据。如果客户端提供的凭据是有效的,交换机将开启端口并允许访问。否则&…

通讯录改进———动态版本

在上一篇博客中讲完了动态内存分配,这时候我们就可以改进之前写的通讯录了,可以将其升级为动态内存的版本,既不用担心联系人满了,也不用担心内存浪费太大。 要将其改为动态版本主要是两件事,首先初始化的时候我们要动…

qt完成对话框提示

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//去掉头部this->setWindowFlag(Qt::FramelessWindowHint);//去掉空白this->setAttribute(Qt::WA_Transl…

Go的数据结构与实现【Queue】

介绍 与栈一样,队列也是最基本的数据结构之一。队列也是值的一种容器,其中值的插入和删除遵循“先进先出”(First-In-First-Out, FIFO)的原则⎯⎯也就是说,每次删除的只能是最先插入的值。 实现 队列的抽象数据类型…

《数据结构学习笔记---第六篇》---栈和队列的实现

目录 1.栈 1.1栈的概念及结构 1.2栈的实现 2.队列 2.1队列的概念及结构 ​2.2队列的实现 3.顺序栈的具体实现 3.1建头文Stack.h” 3.2创建具体接口实现文件Stack.c 3.2.1初始化 3.2.2入栈出栈 3.2.4判空 3.2.5栈的大小 3.2.6销毁栈 3.3主函数的实现 4.链队的具体实现…

SAMRTFORMS 转换PDF 发送邮件

最终成果: *&---------------------------------------------------------------------**& Report ZLC_FIND_EXIT*&---------------------------------------------------------------------**&根据T-CODE / 程序名查询出口、BADI增强*&-------…

2024年大广赛联通沃派命题解析:赛题内容一览

2024大广赛又又又又又出新命题了,它就是助力青少年积极向上,乐观自信,探享多彩人生的5G时代潮牌——联通沃派,让我们来看看命题详情吧! 联联通沃派是中国联通面向青少年群体推出的客户品牌,契合目标群体特…

基于SSM框架的校园失物招领系统:从设计思路到实现细节

末尾获取源码作者介绍:大家好,我是墨韵,本人4年开发经验,专注定制项目开发 更多项目:CSDN主页YAML墨韵 学如逆水行舟,不进则退。学习如赶路,不能慢一步。 目录 一、项目简介 二、开发技术与环…

5.11 Vue配置Element UI框架

Vue配置Element UI框架 目录一、 概要二、 开发前准备1. 搭建Vue框架 三、 安装 Element UI1. 引入 Element UI 依赖2. 在 mian.js 中引入 Element UI 和相关样式:3. 按需引入(非必须, 可忽略)4. 简单构建一个主页面 目录 一、 概要 Element UI 是一个基于 Vue.js …

备考ICA----Istio实验13---使用 Istio Ingress 暴露应用

备考ICA----Istio实验13—使用Istio Ingress TLS暴露应用 1. 环境部署 清理之前实验遗留,并重新部署httpbin服务进行测试 # 清理之前的环境 kubectl delete vs httpbin kubectl delete gw mygateway # 部署httpbin kubectl apply -f istio/samples/httpbin/httpbin.yaml 确认…

vue3使用vuedraggable实现拖拽(有过渡)

1. 安装与使用 vue中vuedraggable安装: pnpm i -S vuedraggablenext或者 yarn add vuedraggablenext注意:vue2和vue3安装的是不同版本的vuedraggable,写法上也会有一些区别。 比如在vue3中使用拖拽,要以插槽的方式,…

【微服务】Sentinel(熔断降级,热点限流)

文章目录 1.熔断降级1.基本介绍1.线程堆积引出熔断降级2.示意图3.熔断,降级,限流三者之间的关系 2.熔断降级策略(以分钟为基本单位)1.慢调用比例2.异常比例3.异常数 3.熔断降级实例—慢调用比例1.需求分析2.com/sun/springcloud/c…

个人简历主页搭建系列-05:部署至 Github

前面只是本地成功部署网站,网站运行的时候我们可以通过 localhost: port 进行访问。不过其他人是无法访问我们本机部署的网站的。 接下来通过 Github Pages 服务把网站部署上去,这样大家都可以通过特定域名访问我的网站了! 创建要部署的仓库…

CAS、AQS、ReentrantLock机制以原理

1、CAS 1.1 基本概念 CAS 是 compare and swap 的简写,即比较并交换。它是指一种操作机制,而不是某个具体的类或方法。在 Java 平台上对这种操作进行了包装。在 Unsafe 类中,调用代码如下 这里无法用Unsafe类看,我使用的是Atomi…

绿联 部署vocechat,搭建私人聊天服务器,用于小型团队和家庭环境

1、镜像 privoce/vocechat-server:latest 2、安装 2.1、基础设置 重启策略:容器退出时总是重启容器。 2.2、网络 桥接即可。 2.3、存储空间 装载路径:/home/vocechat-server/data不可变更,权限读写。 2.4、端口设置 容器端口3000不可变…

鸿蒙OS开发教学:【编程之重器-装饰器】

HarmonyOS 有19种装饰器 必须【2】 绘制一个页面,这两个肯定会用到 EntryComponent 可选【17】 StatePropLinkObjectLinkWatchStylesStoragePropStorageLinkProvideConsumeObservedBuilderBuilderParamLocalStoragePropLocalStorageLinkExtendConcurrent 如果…

python3将exe 转支持库错误 AssertionError: None does not smell like code

exe -> pyc包(*.exe_extracted) 安装反编译工具 exe反编译工具:pyinstxtractor.py下载:https://sourceforge.net/projects/pyinstallerextractor/ python pyinstxtractor.py hello.exe包反编译 懒的写!!! 这有详…

如何使用Zabbix监控MySQL的MGR群集状态

MySQL的MGR(MySQL Group Replication)是MySQL官方提供的一种高可用性和高可靠性的集群解决方案。MGR通过使用基于组复制的方式,实现了多个MySQL实例之间的数据同步和故障转移,从而提供了自动故障恢复和负载均衡的功能。本文将介绍…

安装uim-ui插件不成功,成功解决

安装:这种安装,umi4 不支持,只有umi3才支持。而我发现官网现在默认使用的umi4。 yarn add umijs/preset-ui -D 解决:更改umi版本重新安装umi3 npm i ant-design/pro-cli3.1.0 -g #使用umi3 (指定umi3版本) pro create user-ce…