Vue3 计算属性 computed 实现原理解析

Vue3 计算属性 computed 实现原理解析

一、计算属性核心特性

Vue3 的 computed 属性是响应式系统的核心组成部分,主要实现以下特性:

  1. 延迟计算:只在需要时执行计算
  2. 缓存机制:依赖项未变化时复用计算结果
  3. 自动追踪:自动跟踪响应式依赖关系

二、实现原理拆解

2.1 基础结构

js 复制代码
计算属性的实现基于以下技术要点:
function computed(getter) {
  let value
  let dirty = true // 缓存状态标识

  const effectFn = effect(getter, {
    lazy: true,    // 延迟执行
    scheduler() {  // 调度器
      dirty = true // 触发重新计算
    }
  })

  return {
    get value() {
      if (dirty) {
        value = effectFn()
        dirty = false
      }
      return value
    }
  }
}

2.2 关键实现要素

1. 缓存控制(dirty 变量)
  • 作用:标识计算结果是否需要重新计算

  • 更新时机

    • 初始化时为 true(需要计算)
    • 依赖项变化时通过调度器重置为 true
    • 计算完成后重置为 false
2. effect 机制
  • lazy 模式:延迟执行副作用函数

  • scheduler

    • 响应依赖项变化的回调函数
    • 不直接执行计算,只标记缓存失效
js 复制代码
effect(getter, {
  lazy: true,
  scheduler() {
    if (!dirty) {
      dirty = true
      // 可添加触发更新的逻辑
    }
  }
})
3. 值计算过程
js 复制代码
get value() {
  if (dirty) {
    value = effectFn() // 执行副作用函数
    dirty = false     // 重置缓存标识
  }
  return value
}

三、核心模块协作

3.1 依赖关系建立

  1. 创建 effect 时自动收集依赖
  2. 依赖项变化触发 scheduler
  3. 调度器标记缓存失效

3.2 执行流程示例

sequenceDiagram participant User as 用户访问 participant Computed participant Effect User->>Computed: 访问.value Computed->>Computed: 检查dirty标志 alt dirty为true Computed->>Effect: 执行effectFn() Effect-->>Computed: 返回计算结果 Computed->>Computed: 更新缓存值 else Computed->>User: 直接返回缓存 end

四、与响应式系统的整合

4.1 依赖追踪实现

js 复制代码
// 简化的依赖收集示例
class Dep {
  constructor() {
    this.subscribers = new Set()
  }
  
  depend() {
    if (activeEffect) {
      this.subscribers.add(activeEffect)
    }
  }
  
  notify() {
    this.subscribers.forEach(effect => effect())
  }
}

4.2 响应式联动

当计算属性的依赖项发生变化时:

  1. 触发 setter 操作
  2. 通知关联的 effect
  3. 执行调度器函数
  4. 标记缓存失效
  5. 下次访问时重新计算

五、性能优化要点

  1. 惰性求值:避免不必要的计算
  2. 缓存复用:相同依赖返回相同结果
  3. 最小化触发:依赖变更时才标记失效
  4. 树状缓存:嵌套计算属性形成缓存链

六、完整实现示例

js 复制代码
function computed(getter) {
 let value
 let dirty = true
 let runner = effect(getter, {
   lazy: true,
   scheduler: () => {
     if (!dirty) {
       dirty = true
       // 触发组件更新等后续操作
     }
   }
 })

 return {
   get value() {
     if (dirty) {
       value = runner()
       dirty = false
     }
     return value
   }
 }
}

七、总结要点

  1. 计算属性本质是「可缓存的副作用函数」
  2. 通过 dirty 标志实现缓存有效性控制
  3. effect 的调度器机制实现依赖更新通知
  4. 值访问时才执行实际计算操作
  5. 与响应式系统深度整合实现自动依赖追踪 理解计算属性的实现原理,有助于我们在日常开发中更好地使用和优化计算属性,在复杂场景下做出合理的设计决策。
相关推荐
匹马夕阳14 分钟前
Vite项目中vite.config.js中为什么只能使用process.env,无法使用import.meta.env?
开发语言·前端·javascript
只有一斤了呐19 分钟前
超硬核!教你手搓一套船新架构的前端脚手架~
前端·javascript·开源
拉不动的猪22 分钟前
刷刷题38(前端实现分包及组件懒加载的核心方案&&图片懒加载)
前端·javascript·面试
任磊abc31 分钟前
在react当中利用IntersectionObserve实现下拉加载数据
前端·react·observer·下拉加载·intersection
NaZiMeKiY32 分钟前
HTML5前端第三章节
前端·html·html5
Loadings39 分钟前
Cursor内置的系统提示词学习
前端·javascript·cursor
拉不动的猪44 分钟前
前端数据库indexDB
前端·javascript·面试
自学前端_又又1 小时前
前端苦熬一月,被 Cursor 5 天超越,未来技术浪潮如何破局?
前端·人工智能·cursor
冴羽1 小时前
SvelteKit 最新中文文档教程(4)—— 表单 actions
前端·javascript·svelte
搬砖-无恙1 小时前
vue uniapp里照片多张照片展示
前端·vue.js·uni-app