巨峰驾培计时平台
16.73M · 2025-11-10
computed本身就是一个对象,有value属性,value有getter和setter。getter负责以来收集,setter用来派发更新,但computed大多数场景都是只是应用getter,很少应用setter。
首先解决数据缓存的问题。 computed为了实现缓存,每一个computed都在局部范围内维护了一个变量 dirty。
dirty:当前数据是否为脏数据。
这个computed effect其实就是computed回调包装一层effect函数后得到的产物。
下面是大体流程:
当 computed effect函数执行的时候,会清除先前依赖的响应式变量的depset中的computed effect,这是为了防止无效的重新计算。
然后会将全局维护的 activeEffect 指向 computed effect 作为当前全局唯一激活的effect函数,然后入栈 effectStack 末尾。
之后就执行这个effect的回调,也就是computed的回调。因为computed的回调中访问了其他响应式变量,这些响应式变量的依赖收集的时候,就将当前的activeEffect,也就是当前的computed effect收集到了targetMaps对应的depset中。
然后当响应式派发更新的时候,就会用调度器去执行它depset中所有的effect函数,调度器在执行的时候会先判断effect是否有调度器,因为有一些effect函数不一定是立即执行回调的,可能是在下一轮事件循环执行,也可能是执行其他操作,而 computed effect的时候,就有调度器,调度器会让这个computed 进行 trigger,重新收集依赖,并且将 dirty 重新置为 false,意味着再次访问 computed,会重新计算 computed。
下面是调度器的代码,主要是将dirty标志位变成true,然后再去trigger:
const runner = effect(getter, {
// 延时执行
lazy: true,
// 标记这是一个 computed effect 用于在 trigger 阶段的优先级排序
computed: true,
// 调度执行的实现
scheduler: () => {
if (!dirty) {
dirty = true
// 派发通知,通知运行访问该计算属性的 activeEffect
trigger(computed, "set" /* SET */, 'value')
}
}
})
假如现在响应式变量改变,render effect依赖了computed,trigger就会将computed的depset中的render effect用调度器执行,从而再次访问computed getter,然后就会从新计算值,然后重新将render effect加入到computed的depset中。
这样就实现了computed的响应式。