镇江营销型建站公叿,项目建设情况,怎样在国外网站上做宣传,wordpress新手主题Computed原理
不管在是 Vue 2 还是在 Vue 3 中#xff0c;对 computed 本身的实现原理基本都是一样的。当使用 computed 计算属性时#xff0c;组件初始化会对每一个计算属性都创建对应的 watcher , 然后在第一次调用自己的 getter 方法时#xff0c;收集计算属性依赖的所有…Computed原理
不管在是 Vue 2 还是在 Vue 3 中对 computed 本身的实现原理基本都是一样的。当使用 computed 计算属性时组件初始化会对每一个计算属性都创建对应的 watcher , 然后在第一次调用自己的 getter 方法时收集计算属性依赖的所有 data那么所依赖的 data 会收集这个订阅者同时会针对 computed 中的 key 添加属性描述符创建了独有的 get 方法当调用计算属性的时候这个 get 判断 dirty 是否为 true为真则表示要要重新计算反之直接返回 value。当依赖的 data 变化的时候回触发数据的 set 方法调用 update() 通知更新此时会把 dirty 设置成 true所以 computed 就会重新计算这个值从而达到动态计算的目的。
理解computed原理其实对应着三个问题 computed初始化流程 改变computed的依赖值是如何触发computed值改变的 computed值是如何做到缓存的
computed使用方式
第一种使用方式接受一个 getter 函数并根据 getter 的返回值返回一个不可变的响应式 ref 对象。
const count ref(1)
const a computed(() count.value 1)console.log(a.value) // 2a.value // 错误第二种使用方式接受一个具有 get 和 set 函数的对象用来创建可写的 ref 对象。
const count ref(1)
const a computed({get: () count.value 1,set: val {count.value val - 1}
})a.value 1
console.log(count.value) // 0computed源码
当调用 computed 方法时会根据两种调用方式做一下区分同时调用类 ComputedRefImpl
function computed(getterOrOptions, ...) {let getter;let setter;const onlyGetter isFunction(getterOrOptions);if (onlyGetter) {getter getterOrOptions;setter () {console.warn(Write operation failed: computed value is readonly);};}else {getter getterOrOptions.get;setter getterOrOptions.set;}const cRef new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR);...return cRef;
}ComputedRefImpl 类
class ComputedRefImpl {// 初始化constructor(getter, _setter, isReadonly, isSSR) {this._setter _setter;this.dep undefined;this.__v_isRef true;this._dirty true;this.effect new ReactiveEffect(getter, () {if (!this._dirty) {this._dirty true;triggerRefValue(this);}});this.effect.computed this;this.effect.active this._cacheable !isSSR;// 根据传入是否有setter函数来决定是否只读this[__v_isReadonly /* IS_READONLY */] isReadonly;}get value() {const self toRaw(this);trackRefValue(self);if (self._dirty || !self._cacheable) {self._dirty false;self._value self.effect.run();}return self._value;}set value(newValue) {this._setter(newValue);}
}初始化
ComputedRefImpl 类的第一块就是 computed 的初始化主要做两件事情
创建 effect 对象生成 watcher 监听函数并赋值给实例的 effect 属性。将当前 getter 当做监听函数并附加调度器。设置 computed ref 是否只是可读。设置是否可读的依据是onlyGetter||!setter
不过单单从构造方法来看其实和 computed 没有太大的关系只是进行了初始化变量的操作并创建了一个 ComputedRef 实例赋值给我们的调用。 声明一个 computed 时其实并不会执行 getter 方法只有在读取 computed 值时才会执行它的 getter 方法那么接下来要关注 ComputedRefImpl 的 getter 方法。
执行getter方法
第二部分就是 getter 方法的执行getter 方法会在读取 computed 值的时候执行而在 getter 方法中有一个叫 _dirty 的变量它的意思是代表脏数据的开关默认初始化时 _dirty 被设为 true 在 getter 方法中表示开关打开需要计算一遍 computed 的值然后关闭开关之后再获取 computed 的值时由于 _dirty 是 false 就不会重新计算。这就是 computed 缓存值的实现原理。
get value() {...if (self._dirty || !self._cacheable) {self._dirty false;self._value self.effect.run();}return self._value;
}那么 computed 是怎么知道要重新计算值的呢
computed 本身是依赖响应式属性的变化的如果依赖的响应属性发生改变会触发 effect 的 scheduler 函数执行。此方法就是 computed 内部依赖的状态变化时会执行的操作。所以最终的流程就是computed 内部依赖的状态发生改变执行对应的监听函数这其中自然会执行 scheduler 里的操作。而在 scheduler 中将 _dirty 设为了 true 。
this.effect new ReactiveEffect(getter, () {// effect 的 scheduler 函数执行if (!this._dirty) {this._dirty true;triggerRefValue(this);}
});那么computed 是怎么知道内部依赖产生了变化呢这是由于在我们第一次获取 computed 值即执行 getter 方法 的时候对内部依赖进行了访问在那个时候就对其进行了依赖收集操作所以 computed 能够知道内部依赖产生了变化。
注意上面提到的「第一次获取 computed 值」这里是第一次get而不是初始化 computed。
总结
总结来说computed在第一次get的时候在内部收集了依赖并将内部缓存开关设为了false此后只有在依赖改变的时候才会将内部缓存开关设为true从而使computed的值发生改变。