vue 3 effect作用与原理

news/2025/2/7 8:27:55/文章来源:https://www.cnblogs.com/is-DW/p/18701983

Vue 3 的 Effect(副作用) 是整个响应式系统的核心机制,负责管理依赖追踪和响应式触发。理解其作用和原理对掌握 Vue 的底层机制至关重要。


一、核心作用

1. 依赖追踪(Dependency Tracking)

  • 自动跟踪响应式数据在副作用函数中的使用。
  • 示例代码
    import { reactive, effect } from 'vue'const obj = reactive({ count: 0 })effect(() => {console.log(`count is: ${obj.count}`)
    })
    
    • 当首次执行 effect 时,函数 () => console.log(...) 会被运行。
    • 触发 obj.countget 操作,触发依赖收集(将当前 effect 关联到 obj.count)。

2. 自动响应(Automatic Re-run)

  • 当响应式数据的依赖变化时,自动重新执行副作用函数:
    obj.count++  // 触发依赖更新,控制台打印 "count is: 1"
    

3. 支撑高级 API

  • computedwatch、组件渲染函数等底层都依赖于 effect 实现。

二、实现原理

1. 核心类:ReactiveEffect

Vue 3 用 ReactiveEffect 类封装副作用逻辑,简化后的源码结构如下:

class ReactiveEffect<T = any> {// 当前 effect 的所有依赖项(其他响应式对象)deps: Dep[] = []// 构造函数参数constructor(public fn: () => T,            // 副作用函数public scheduler?: () => void  // 调度函数(控制重新执行方式)) {}// 运行副作用(触发依赖收集)run() {activeEffect = this // 标记当前正在运行的 effecttry {return this.fn()} finally {activeEffect = undefined}}// 停止侦听stop() { /* 从所有依赖中移除自身 */ }
}

2. 依赖收集流程(Track)

  • 数据结构
    type Dep = Set<ReactiveEffect>    // 依赖集合
    type TargetMap = WeakMap<Object, Map<string, Dep>> // 全局依赖存储
    
  • 触发时机:响应式数据的 get 操作触发时。
  • 流程
    1. 根据响应式对象 (target) 和键 (key) 找到存入 targetMap 的依赖集合 (dep)。
    2. 将当前活跃的 activeEffect 添加到 dep 中。
    3. 同时将 dep 加入 activeEffect.deps(反向记录,用于 cleanup)。

3. 触发更新(Trigger)

  • 触发时机:响应式数据的 set 操作时。
  • 流程
    1. 根据 targetkeytargetMap 获取对应的 dep 集合。
    2. 遍历 dep 中所有 effect
    • 如果有 scheduler(如 computed),执行调度器(优化性能)。
    • 否则直接执行 effect.run()

4. 调度器(Scheduler)

  • 允许控制 effect 如何重新执行:
    effect(() => {console.log(obj.count)
    }, {scheduler(effect) { // 如将 effect 推入微任务队列中异步执行queueMicrotask(effect.run) }
    })
    
  • 应用场景:
    • watch 的异步批处理更新。
    • computed 的值懒更新。

三、关键优化设计

1. 嵌套 Effect 栈

  • 用栈结构 effectStack 跟踪嵌套的 effect:
    function run() {if (!effectStack.includes(this)) {try {effectStack.push((activeEffect = this))return this.fn()} finally {effectStack.pop()activeEffect = effectStack[effectStack.length - 1]}}
    }
    
    • 解决问题:组件嵌套时的依赖关系混乱。

2. Cleanup 机制

  • 每次 effect 执行前清理旧依赖:
    function run() {cleanup(this) // 清理之前收集的旧依赖// ...然后重新收集新依赖
    }
    
    • 解决问题:动态分支逻辑导致的无效依赖(如 v-if 切换导致的条件依赖)。

3. Lazy 执行

  • 可配置不立即执行 effect:
    const runner = effect(fn, { lazy: true })
    runner() // 手动执行
    
    • 应用场景: computed 属性初始化时延迟计算。

四、与 Vue 各组件的关联

1. 组件渲染

  • 组件 render 函数被包裹在 effect 中:
    function setupRenderEffect(instance) {effect(() => {const subTree = instance.render.call(instance.proxy)patch(instance.subTree, subTree)instance.subTree = subTree}, { scheduler: queueJob }) // 异步更新队列
    }
    

2. Computed 实现

  • computed 通过 effect + 调度器实现懒更新:
    const computedRef = new ComputedRefImpl(getter,() => { // 调度器if (!this._dirty) {this._dirty = truetrigger(this, 'set', 'value')}}
    )
    

3. Watch API

  • watch 基于 effect 的调度器实现异步回调:
    function watch(source, cb, { flush } = {}) {let schedulerif (flush === 'sync') {scheduler = cb} else { // 'post' 或其他默认情况scheduler = () => queuePostFlushCb(cb)}effect(() => traverse(source), { scheduler })
    }
    

五、与 Vue 2 的对比

特性 Vue 2 (Watcher) Vue 3 (Effect)
依赖追踪 通过遍历数据触发 getter 通过 Proxy/Reflect 自动追踪
更新粒度 依赖组件级检查 基于精确依赖的靶向更新
性能优化 需手写 pureComputed 内置自动的依赖清理和调度机制
内存管理 易产生内存泄漏(旧 Dep 引用问题) 通过 WeakMap 自动释放无用依赖

六、源码流程图解

+---------------------+
|   Reactive Object   |
+----------+----------+│ 访问属性时▼
+---------------------+
|   触发 get 代理     +----→ track(target, key)
+---------------------+         │▲                    ▼ 存储依赖关系│          +---------------------++----------+    targetMap        || (WeakMap结构)        |+---------+-----------+│▼+---------------------+|   depsMap (Map)     || (key → Dep Set)      |+---------+-----------+│▼+---------------------+|   dep (Set)         || (存储所有关联的 effect)|+---------------------+

总结

Vue 3 的 effect 通过以下机制成为响应式系统的核心:

  1. Proxy 依赖收集:精确追踪响应式数据的使用。
  2. 调度器控制:提供灵活的回调执行方式。
  3. 内存安全:通过 WeakMap 自动管理依赖。
  4. 框架级优化:支持组件渲染、计算属性、watch 等核心功能。

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

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

相关文章

ZW3D二次开发_入门_Action与Ribbon菜单定制--转自 知乎 捣蛋龙

ZW3D二次开发_入门_Action与Ribbon菜单定制捣蛋龙 ​关注他5 人赞同了该文章​ 目录收起ZW3D二开入门目录 - 知乎 (zhihu.com)最新测试环境:2025 SP前言定制Ribbon菜单1.新建工作区2.定义"行为"3.定义自定义Ribbon文件4.编写策略文件5.编写引导程序6.多环境差异化策…

day4

简单图论与构造 A 考虑把权值为 2 的点看作给权值为 1 的点加一, 所以整个问题被拆成了两个部分:构造树和给节点加一 事实上,在第一部分时我们将树构造的尽量平衡是有好处,这个结论在第二个步骤中会得到证明 构造: Process DFS(father,ch,u,size):if size==0 then returnso…

Omnissa Horizon Windows OS Optimization Tool 2412 - Windows 系统映像优化工具

Omnissa Horizon Windows OS Optimization Tool 2412 - Windows 系统映像优化工具Omnissa Horizon Windows OS Optimization Tool 2412 - Windows 系统映像优化工具 Optimizing Images Using Omnissa Horizon Windows OS Optimization Tool 请访问原文链接:https://sysin.org/…

BOM最全基础信息:标准件、通用件、替换件、必选件

在生产制造领域,物料清单(BOM)是产品设计、生产计划和供应链管理的核心基础。本文系统梳理了BOM中各类零部件的分类方法,供大家参考。在生产制造的复杂领域中,我们会与各式各样的产品组成部分打交道。清晰、准确地对它们进行分类,并实施有效的管理,对于提升生产效率、保…

人工智能辅助芯片设计

芯片设计:一个近乎无限的问题空间 设计复杂性呈指数级增长 设计复杂性的含义 一连串棘手的问题 贯穿整个流程优化 HDL生成研究 使用GCN加速设计评估 人工智能辅助验证 参考文献链接https://www.hc2024.hotchips.org/assets/program/tutorials/3-HC24.synopsys.SteliosDiaman…

应用随机过程 | 期末 cheat sheet

出分后发布笔记……这篇博客汇总了「应用随机过程」2018 - 2022 的期末试题,并根据题型分类总结。 本站相关博客:应用随机过程 | 期末知识点总结特别鸣谢:知乎 | 九一居士 |《应用随机过程》课程笔记系列目录1 马尔可夫链计算题2 常返的马尔可夫链3 连续时间参数的马尔可夫链…

推荐《AI芯片开发核心技术详解》、《智能汽车传感器:原理设计应用》、《TVM编译器原理与实践》、《LLVM编译器原理与实践》4本书,非常感谢

4本书推荐《AI芯片开发核心技术详解》、《智能汽车传感器:原理设计应用》、《TVM编译器原理与实践》、《LLVM编译器原理与实践》由清华大学出版社资深编辑赵佳霓老师策划编辑的新书《AI芯片开发核心技术详解》已经出版,京东、淘宝天猫、当当等网上,相应陆陆续续可以购买。该…

OpenVX基本原理与历史

OpenVX基本原理 2.1 引言 2.1.1 摘要 OpenVX 是一个低级编程框架域,用于支持软件开发人员,可高效访问计算机视觉硬件加速功能和性能的可移植性。OpenVX 旨在支持现代硬件架构,例如,移动和嵌入式 SoC 以及桌面系统。其中许多系统是并行和异构的:多个处理器类型包括多核 CPU…

L4D2自制角色Mod - HUI篇

如何以相对简易的思路自制求生之路2求生者头像Mod本文是笔者尝试制作 求生之路2 角色 Mod 的过程中编写的笔记,笔者的背景是有基础的计算机知识和图像处理软件的使用经验,相信大多数读者朋友都有同样的水平。本文面向希望能快速简单地自定义游戏内角色图像/模型,但对更深层次…

使用Netty与前端请求进行交互实现实时通讯

引言因为不满足与一般的SpringBoot CRUD开发(太无聊了)所以去学一下网络编程,第一站就是通过B站老罗的EasyChat项目了解到了Netty这个网络框架,在学习这个项目之前也是去学习了一下Netty框架的使用以及相关的原理知识所以是有一定了解的,但是只是一味的学习不去实践总感觉是空中…

如何使用 Filebeat 8 连接 Easysearch

在日志场景,还是有很多小伙伴在使用 Filebeat 采集日志的。今天我来实战下使用 Filebeat 8 连接 Easysearch 。本次使用 Easysearch-1.9.0 版本和 Filebeat-8.17.0 版本做演示,也适用 Filebeat-oss-8.17.0 版本。 Easysearch 不开启兼容参数的情况 Easysearch 默认情况下未开…