计算属性默认是有缓存的,内部实现参考源码
src/core/instance/state.js
调用initComputed()
方法,创建 watcher
/**
* 初始化 computed
* @param {*} vm
* @param {*} computed
*/
function initComputed (vm: Component, computed: Object) {
// $flow-disable-line
// 创建 watcher(lazy为true, 默认 dirty 为true, 默认watcher 不执行)
const watchers = vm._computedWatchers = Object.create(null)
// computed properties are just getters during SSR
const isSSR = isServerRendering()
// 便利 computed 对象中的所有key
for (const key in computed) {
// 部分代码略 ....
// component-defined computed properties are already defined on the
// component prototype. We only need to define computed properties defined
// at instantiation here.
// 如果在组件上不存在这个属性
if (!(key in vm)) {
// 定义这些key 到 computed 计算属性上
defineComputed(vm, key, userDef)
}
}
}
接着看 defineComputed(), 这个方法就是 将属性定义到实例上
// 将属性 定义到 实例上
export function defineComputed (
target: any,
key: string,
userDef: Object | Function
) {
// const shouldCache = !isServerRendering()
// if (typeof userDef === 'function') {
// sharedPropertyDefinition.get = shouldCache
// ? createComputedGetter(key)
// : createGetterInvoker(userDef)
// sharedPropertyDefinition.set = noop
// } else {
// sharedPropertyDefinition.get = userDef.get
// ? shouldCache && userDef.cache !== false
// ? createComputedGetter(key)
// : createGetterInvoker(userDef.get)
// : noop
// sharedPropertyDefinition.set = userDef.set || noop
// }
// if (process.env.NODE_ENV !== 'production' &&
// sharedPropertyDefinition.set === noop) {
// sharedPropertyDefinition.set = function () {
// warn(
// `Computed property "${key}" was assigned to but it has no setter.`,
// this
// )
// }
// }
// 重新定义这些属性到实力上
Object.defineProperty(target, key, sharedPropertyDefinition)
}
用户取值的缓存处理在 createComputedGetter()
方法中
// 创建getter 当用户取值时,会执行此方法
function createComputedGetter (key) {
return function computedGetter () {
const watcher = this._computedWatchers && this._computedWatchers[key]
// 当用户取值时
if (watcher) {
// 如果dirty 为true
if (watcher.dirty) {
// 计算结果(同时会进行依赖收集, dirty 改为false)
watcher.evaluate()
}
if (Dep.target) {
watcher.depend()
}
// 如果是false, 直接返回上次计算的结果
return watcher.value
}
}
}
源码逻辑总结:
- 调用
initComputed()
初始化计算属性 - 创建 watcher 实例(这个时候,默认lazy为true, dirty 为true, watcher默认不执行)
- 调用
defineComputed()
方法,将属性定义到 实例上去 - 通过
createComputedGetter()
这个方法用于用户的取值操作 - 在这个方法中,当用户取值时, 会判断 dirty,
- 如果为true, 调用
watcher.evaluate()
计算结果,并进行依赖收集,dirty变为false - 如果为false, 直接返回上次计算的结果
- 如果为true, 调用