认识
一、认识
Vue.js 3.0
中, computed
是一个计算属性, 根据传入的 getter
函数, 计算得到一个可读或者可读可写的响应式数据。 computed
本质上是将传入的 getter
作为一个副作用函数, 创建一个带有 lazy
和 scheduler
的 effect
, 返回一个具有访问器属性value
和 设置器属性value
的数据。在读取 computed
数据时, 访问器进行拦截, 在内部变量 dirty
为 true
的情况下, 执行通过 effect
返回的 effectFn
函数, 这个 effectFn
内部会执行 computed
传入的 getter
进行计算。基本机制如下所示:
function computed(getter){
let value;
let dirty = true;
const effectFn = effect(getter,{
lazy: true,
schedular(){
dirty = true;
}
});
const obj = {
get value(){
if(dirty){
value = effectFn();
dirty = false;
}
return value;
}
}
}
二、类细节
2.1 class
get value
class Test{
get value(){
}
}
const test = new Test();
console.log(test.value);
set value
class Test{
set value(newValue){
}
}
const test = new Test();
test.value = xxx;
三、变量细节
3.1 value
value
通过 value
保存 effectFn()
的结果, 也就是存储上一次的计算值。
3.2 dirty
dirty
通过 dirty
控制 effectFn
是否执行、重新计算, 从而实现了 computed
的缓存。访问 computed
的值多次, 只会在第一次访问时进行真正的计算, 后续访问都会直接读取缓存的 value
值。也就是控制 computed
是否要重新计算。
四、函数细节
4.1 get
当访问 computed.value
时, get
访问器会进行拦截, 如果此时的 dirty
为 true
, 开始执行 effect
的返回值 effectFn
也就是 computed
传入的 getter
计算结果。并收集与这个 computed
相关的副作用函数。
4.2 effect
computed
函数接受一个 getter
作为参数, 将 getter
函数作为副作用函数, 创建一个带有 lazy
和 schedular
的 effect
。 传入的配置如下:
const effect = effect(getter,{
lazy: true,
scheduler(){
}
});
-
lazy
的作用是懒执行effect
传入的回调 -
scheduler
是调取器, 当computed
数据依赖的响应式数据发生变化, 会执行scheduler
中的逻辑。 在scheduler
调度器中, 主要是将dirty
置为true
, 调用trigger
触发computed
的相关的副作用函数重新执行。
4.3 getter
computed
函数接受一个 getter
作为参数, 将 getter
函数作为副作用函数, 创建一个带有 lazy
和 schedular
的 effect
。此时 , effect
会返回一个函数 effectFn
, 这个函数的内部会执行 getter
。
4.4 schedular
scheduler
为 effect
的调度器, 可以控制副作用函数的执行顺序与执行次数。如果 effect
存在 scheduler
配置项, 当响应式数据发生变化时, 会触发 scheduler
调度函数执行, 而不是直接触发副作用函数。
五、问题
5.1 computed vs watch
watch
用于监测响应式数据, 当数据发生变化时, 通知并执行相应的回调函数。watch
传入的第一个参数为要监测的响应式数据, watch
中创建一个 effect
副作用, 第一个参数为封装好副作用函数, 这个副作用函数主要是读取传入的响应式数据, 触发响应式数据的副作用收集机制, 传入 Scheduler
配置项, 在 effect
中, 如果有 Scheduler
配置项, 那么执行 Scheduler
调度函数执行, 而不是直接触发副作用函数执行。在 Scheduler
调度函数中, 执行传入的 watch
回调。watch
有三个参数, 侦听器的源, 发生变化的回调, 和一个配置项, 可以配置 immediate
立即监听, 可以配置 deep
进行深度监听。 在变化的回调中, 同样提供了三个参数, 最新值, 旧值, 以及一个用于注册副作用清理的回调函数 cleanup
。 cleanup
可以用于解决一些竟态问题, 在响应式数据发生变化后, 调用 cleanup
, 并传入想要取消的逻辑代码, 优先取消之前的副作用影响后,再开始新的副作用。
computed
是一个计算属性, 根据传入的 getter
函数, 计算得到一个可读或者可读可写的响应式数据。 computed
本质上是将传入的 getter
作为一个副作用函数, 创建一个带有 lazy
和 scheduler
的 effect
, 返回一个具有访问器属性value
和 设置器属性value
的数据。在读取 computed
数据时, 访问器进行拦截, 在内部变量 dirty
为 true
的情况下, 执行通过 effect
返回的 effectFn
函数, 这个 effectFn
内部会执行 computed
传入的 getter
进行计算。因此, computed
同 ref
一样, 是一个新的状态数据, 并具有延时计算和缓存计算结果的功能。