欢迎来到科站长!

JavaScript

当前位置: 主页 > 网络编程 > JavaScript

vue 3 effect作用与原理解析

时间:2025-02-07 08:55:11|栏目:JavaScript|点击:

目录

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

2. 依赖收集流程(Track)

数据结构

type Dep = Set    // 依赖集合
type TargetMap = WeakMap> // 全局依赖存储
  • 触发时机:响应式数据的 get 操作触发时。
  • 流程

    根据响应式对象 (target) 和键 (key) 找到存入 targetMap 的依赖集合 (dep)。

    将当前活跃的 activeEffect 添加到 dep 中。

    同时将 dep 加入 activeEffect.deps(反向记录,用于 cleanup)。

3. 触发更新(Trigger)

  • 触发时机:响应式数据的 set 操作时。
  • 流程

    根据 targetkeytargetMap 获取对应的 dep 集合。

    遍历 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 = true
      trigger(this, 'set', 'value')
    }
  }
)

3. Watch API

watch 基于 effect 的调度器实现异步回调:

function watch(source, cb, { flush } = {}) {
  let scheduler
  if (flush === 'sync') {
    scheduler = cb
  } else { // 'post' 或其他默认情况
    scheduler = () => queuePostFlushCb(cb)
  }
  effect(() => traverse(source), { scheduler })
}

五、与 Vue 2 的对比

六、源码流程图解

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

总结

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

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

到此这篇关于vue 3 effect作用与原理的文章就介绍到这了,更多相关vue 3 effect作用内容请搜索科站长以前的文章或继续浏览下面的相关文章希望大家以后多多支持科站长!

上一篇:Node.js调用DeepSeek API的完整指南

栏    目:JavaScript

下一篇:JavaScript实现秒数转换时间的两种格式

本文标题:vue 3 effect作用与原理解析

本文地址:https://www.fushidao.cc/wangluobiancheng/3168.html

广告投放 | 联系我们 | 版权申明

申明:本站所有的文章、图片、评论等,均由网友发表或上传并维护或收集自网络,属个人行为,与本站立场无关。

如果侵犯了您的权利,请与我们联系,我们将在24小时内进行处理、任何非本站因素导致的法律后果,本站均不负任何责任。

联系QQ:257218569 | 邮箱:257218569@qq.com

Copyright © 2018-2025 科站长 版权所有冀ICP备14023439号