Vue3 计算属性 computed 实现原理解析
一、计算属性核心特性
Vue3 的 computed
属性是响应式系统的核心组成部分,主要实现以下特性:
- 延迟计算:只在需要时执行计算
- 缓存机制:依赖项未变化时复用计算结果
- 自动追踪:自动跟踪响应式依赖关系
二、实现原理拆解
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 依赖关系建立
- 创建 effect 时自动收集依赖
- 依赖项变化触发 scheduler
- 调度器标记缓存失效
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 响应式联动
当计算属性的依赖项发生变化时:
- 触发 setter 操作
- 通知关联的 effect
- 执行调度器函数
- 标记缓存失效
- 下次访问时重新计算
五、性能优化要点
- 惰性求值:避免不必要的计算
- 缓存复用:相同依赖返回相同结果
- 最小化触发:依赖变更时才标记失效
- 树状缓存:嵌套计算属性形成缓存链
六、完整实现示例
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
}
}
}
七、总结要点
- 计算属性本质是「可缓存的副作用函数」
- 通过 dirty 标志实现缓存有效性控制
- effect 的调度器机制实现依赖更新通知
- 值访问时才执行实际计算操作
- 与响应式系统深度整合实现自动依赖追踪 理解计算属性的实现原理,有助于我们在日常开发中更好地使用和优化计算属性,在复杂场景下做出合理的设计决策。