Vue3响应式原理实现与track和trigger依赖收集和触发依赖

前言

Vue的响应式系统是基于数据劫持加发布订阅者模式实现的,数据响应式就是建立响应式数据依赖的关系 (调用了响应式数据的操作之间的关系)
vue2使用Object.defineProperty进行数据拦截,而Vue3使用Proxy进行数据拦截是es6中新加的api,比Object.defineProperty解除了很多限制,性能更加优秀

Proxy

利用Proxy代理对象进行数据劫持

Proxy的基本使用
const testobj= { count: 0 };
const proxy = new Proxy(testobj, {
get(target, key) {
console.log('触发get')
return Reflect.get(target, key)
},
set(target, key, value) {
console.log('触发set')
return Reflect.set(target, key, value)
},
});
console.log(proxy.count) // 触发get
proxy.count = 1 // 触发set

在Vue3中,会通过拦截 getset 操作来实现依赖收集和触发依赖。当我们访问响应式对象的属性时,会触发 get 操作,此时 Vue3 会将当前的依赖(effect)项添加到依赖列表中;当我们修改响应式对象的属性时,会触发 set 操作,此时 Vue3 会遍历依赖列表,调用每个依赖项的更新函数,对视图进行更新。

所以先定义依赖类,需要有数据结构来存储依赖,
effect副作用函数,这个函数在响应式数据发生变化时会被自动触发,从而执行相关的操作。可以完善effect副作用函数来控制响应式数据
// 定义的依赖类
class ReactiveEffect{private _fn_;constructor(fn){this._fn_ = fn}run(){activeEffect = thisthis._fn_()}
}
let activeEffect;
//effect副函数
//传入一个直接执行的函数
function effect(fn){const _effect = new ReactiveEffect(fn)_effect.run()
}

当访问响应式对象的属性时,会添加一个依赖项,并将当前的 activeEffect 类保存到一个 effects 集合中,而 effects 集合则以 target 对象为键,以保存在该对象上的依赖项的列表为值。这也就是track收集依赖

为什么用WeakMap做数据结构呢?weakMap重要在它的弱字,WeakMap 中的键是弱引用的,意味着,当键不再被其他地方引用时,垃圾回收器可以自动清除这些键对应的值。可以优化性能
const targetMap = new WeakMap()//收集依赖function track(target, key) {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)
}
//简化下代码
function track(target, key) {const depsMap = targetMap.get(target) || new Map();targetMap.set(target, depsMap);const dep = depsMap.get(key) || new Set();depsMap.set(key, dep);dep.add(activeEffect);}
trigger触发依赖是当响应式对象属性修改时,系统会遍历依赖项列表,逐个执行保存在其中的 activeEffect 类,代表了对应依赖项的操作。
function trigger(target,key) {const depsMap = targetMap.get(target)const deps = depsMap.get(key)for(const effect of deps){effect.run()}
}
这下可以根据上述实现一波reactive实现
let activeEffect;
function isObject(raw) {
if (raw === null) {
return false
} else if (typeof raw === 'object' || typeof raw === 'function') {
return true
} else {
return false
}
}
function reactive(raw){if (!isObject(raw)) {console.warn(`${raw} not object`)return raw}return new Proxy(raw,{get(target, key) {const res =Reflect.get(target, key)track(target,key)return res},set(target,key,value){const res = Reflect.set(target, key, value)trigger(target,key,value)return res //这是个布尔值}		})
}
//实现依赖类和effect函数
class ReactiveEffect{_fn_;constructor(fn){this._fn_ = fn}run(){activeEffect = this;this._fn_();}}function effect(fn){const _effect = new ReactiveEffect(fn)_effect.run()}
const targetMap = new WeakMap()//收集依赖
function track(target, key) {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)}//触发依赖
function trigger(target,key) {const depsMap = targetMap.get(target)const deps = depsMap.get(key)for(const effect of deps){effect.run()
}
}

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

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

相关文章

对Windows超融合S2D的一些补充

先说一个不知道算不算BUG的例子,下面这个存储池是用两台服务器各2块10G建立的,除去系统保留的部分,显示还有13G可用。 但如果使用其新建虚拟磁盘会显示可用的空间为0 然后我又各增加了一块10G硬盘进池,变成了可用空间为30.5GB …

JavaEE之线程(4)——线程安全、线程安全的原因,synchronized关键字

前言 在本栏的前面的内容中,我们介绍了线程的创建、Thread 类及常见方法、线程的状态,今天我们来介绍一下关于线程的另一个重点知识——线程安全。 一、线程安全 基本概念: 线程安全的确切定义是复杂的,但我们可以这样认为&…

哪里可以找到可靠的代理IP?

需要代理来访问受限制的网站或改善您的在线隐私?别再犹豫了!在这篇博文中,我们将探讨您可以使用的选项,并提供有关在哪里获取代理的指导。 首先,让我们了解什么是代理及其工作原理。代理充当您的设备和互联网之间的中介…

mybatis 设置字段值为null 不生效不起作用 解决办法

mybatis 设置字段值为null 不生效不起作用 解决办法 问题 updateObj.setPublishTime(null);int update protocolMapper.updateById(updateObj);执行之后,不生效,数据库里仍有值 解决 在需要设置null的字段加上 TableField(updateStrategy FieldStra…

《Mybatis》系列文章目录

什么是 MyBatis? MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO&#xff…

【触想智能】无风扇工控一体机的优点与定制要求分析

随着工业自动化的不断推进,工控一体机作为自动化生产的核心设备,在工业生产中发挥着越来越重要的作用。 在工控一体机的设计中,散热是一个非常关键的问题,而无风扇工控一体机的出现为解决这个问题提供了新方法。 无风扇工控一体机…

Web常见的攻击方式及其防御策略

随着互联网技术的快速发展,Web应用已成为我们日常生活和工作中不可或缺的一部分。然而,Web应用也面临着各种安全威胁和攻击。了解这些常见的攻击方式,并采取有效的防御策略,对于保护Web应用的安全至关重要。 一、常见的Web攻击方…

Python lambda函数

Python lambda函数 Python中的lambda函数,用于创建简洁的匿名函数。Lambda函数通常用于在需要函数作为参数的上下文中,以及在需要临时定义简单函数的地方。 下面是一些关于lambda函数的基本知识和用法: 1. lambda函数的基本语法 lambda argum…

Rx(Reactive Extensions)的由来

既然我们已经介绍了响应式编程,现在是时候了解我们的明星了:响应式扩展,通常简称为Rx。微软开发了Reactive扩展库,使其易于处理事件流和数据流。在某种程度上,时变值本身就是一个事件流;每个值更改都是一种类型的事件它会更新依赖…

【AHK】固定wps的窗口大小/解决wps2019版重新打开窗口会缩小至100*100的bug

解决办法就是每一次点击lbutton添加触发事件,同样也可以换成其他快捷键 #IfWinActive ahk_exe wpp.exe ~lbutton:: justfyWin(ahk_exe wpp.exe) #IfWinActive#IfWinActive ahk_exe wps.exe ~lbutton:: justfyWin(ahk_exe wps.exe) return #IfWinActive#IfWinActive …

使用Docker安装Nginx

一、Nginx介绍 Nginx 是一款高性能的开源 Web 服务器和反向代理服务器,具有高效能、高稳定性、低资源消耗等优点。可以处理大量并发请求,支持多种协议,还能实现负载均衡、缓存等功能,在互联网应用中被广泛使用。在Nginx中&#xf…

【数据可视化01】matplotlib实例介绍1

目录 一、引言二、实例介绍1.柱状图1)简单柱状图2)堆叠柱状图 2.线条形式3.折线图(多子图)4.散点图5.水平和垂直线条6.饼状图1)饼状图2)“条形饼”图 一、引言 matplotlib是一个用于绘制数据可视化的Python库。它可以创建各种静态…

想在先锋文汇发表文章?看看投稿方法吧

、 1. 主题明确:选择一个鲜明的主题,与党的工作和中心任务相关。可以选择与当前热点问题、党的路线方针政策有关的话题,以各级党组织开展的活动、党员先进事迹等为素材。编辑【yangwei013049】 2. 紧密联系实际:文章要贴近实际&…

虚拟资源在线交易服务平台源码 线上虚拟商品交易平台搭建

在信息爆炸的时代,虚拟资源、素材、源码系统等等以其独特的魅力,逐渐成为人们日常生活和工作中不可或缺的一部分。如何高效地获取、管理和交易这些虚拟资源,分享一款虚拟资源在线交易服务平台源码,轻松搭建线上虚拟商品交易平台&a…

C++之Eigen库基本使用(下)

1、常见变换 Eigen::Matrix3d //旋转矩阵(3*3) Eigen::AngleAxisd //旋转向量(3*1) Eigen::Vector3d //欧拉角(3*1) Eigen::Quaterniond //四元数(4*1) Eigen::Isom…

STL库具体容器与用法

vector动态数组: 算法&#xff1a;for_each迭代器&#xff1a;vector<int>::iterator 头文件:<vector> 声明&#xff1a;vector<数据类型> 变量名 定义一个整形的vector容器&#xff1a;vector<int> v 迭代器&#xff1a;vector<数据类型>:…

drm 和 sysfs

DRM 全称是Direct Rendering Manager&#xff0c;进行显示输出管理、buffer 分配、帧缓冲。对应userspace 库为libdrm&#xff0c;libdrm 库提供了一系列友好的控制封装&#xff0c;使用户可以方便的进行显示的控制和buffer 申请。 DRM的设备节点为"/dev/dri/cardX"…

Docker运行出现iptables: No chain/target/match by that name报错如何解决?

在尝试重启 Docker 容器时遇到的错误信息表明有关 iptables 的配置出了问题。这通常是因为 Docker 需要配置网络&#xff0c;而 iptables 规则没有正确设置或被意外删除。具体到你的错误信息中&#xff0c;报错 iptables: No chain/target/match by that name 表示 Docker 尝试…

深入理解与应用C++ Vector

1. C Vector 简介与基本使用 C 的 vector 是一个序列容器&#xff0c;用于表示可变大小的数组。它结合了数组的高效元素访问和动态大小调整的灵活性。与静态数组相比&#xff0c;vector 的大小可以根据需要自动调整&#xff0c;这是通过在底层使用动态数组来实现的。当新元素被…

[原创](Modern C++)现代C++的Lambda表达式常规概念以及细节探讨

[简介] 常用网名: 猪头三 出生日期: 1981.XX.XX QQ联系: 643439947 个人网站: 80x86汇编小站 https://www.x86asm.org 编程生涯: 2001年~至今[共22年] 职业生涯: 20年 开发语言: C/C、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python 开发工具: Visual Studio、D…