综合开发

vue的computed实现原理

微信扫一扫,分享到朋友圈

vue的computed实现原理

1.每个computed属性都会生成对应的观察者(Watcher实例),观察者存在values属性和get方法。computed属性的getter函数会在get方法中调用,并将返回值赋值给value。初始设置dirty和lazy的值为true,lazy为true不会立即get方法(懒执行),而是会在读取computed值时执行。

function initComputed (vm, computed) {
var watchers = vm._computedWatchers = Object.create(null);
var isSSR = isServerRendering();
for (var key in computed) {
var userDef = computed[key];
var getter = typeof userDef === 'function' ? userDef : userDef.get;
...
if (!isSSR) {
watchers[key] = new Watcher(// 生成观察者(Watcher实例)
vm,
getter || noop,// getter将在观察者get方法中执行
noop,
computedWatcherOptions // { lazy: true }懒执行,暂不执行get方法,当读取computed属性值执行
);
}
if (!(key in vm)) {
defineComputed(vm, key, userDef);
} else if (process.env.NODE_ENV !== 'production') {
if (key in vm.$data) {
warn(("The computed property "" + key + "" is already defined in data."), vm);
} else if (vm.$options.props && key in vm.$options.props) {
warn(("The computed property "" + key + "" is already defined as a prop."), vm);
}
}
}
}

2.将computed属性添加到组件实例上,并通过get、set获取或者设置属性值,并且重定义getter函数,

function defineComputed (
target,
key,
userDef
) {
var shouldCache = !isServerRendering();
if (typeof userDef === 'function') {
sharedPropertyDefinition.get = shouldCache // 重定义getter函数
? 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);// 将computed属性添加到组件实例上
}
// 重定义的getter函数
function createComputedGetter (key) {
return function computedGetter () {
var watcher = this._computedWatchers && this._computedWatchers[key];
if (watcher) {
if (watcher.dirty) {// true,懒执行
watcher.evaluate();// 执行watcher方法后设置dirty为false
}
if (Dep.target) {
watcher.depend();
}
return watcher.value //返回观察者的value值
}
}
}

3.页面初始渲染时,读取computed属性值,触发重定义后的getter函数。由于观察者的dirty值为true,将会调用get方法,执行原始getter函数。getter函数中会读取data(响应式)数据,读取数据时会触发data的getter方法,会将computed属性对应的观察者添加到data的依赖收集器中(用于data变更时通知更新)。观察者的get方法执行完成后,更新观察者的value值,并将dirty设置为false,表示value值已更新,之后在执行观察者的depend方法,将上层观察者(该观察者包含页面更新的方法,方法中读取了computed属性值)也添加到getter函数中data的依赖收集器中(getter中的data的依赖器收集器包含computed对应的观察者,以及包含页面更新方法(调用了computed属性)的观察者),最后返回computed观察者的value值。

4.当更改了computed属性getter函数依赖的data值时,将会根据之前依赖收集的观察者,依次调用观察者的update方法,先调用computed观察者的update方法,由于lazy为true,将会设置观察者的dirty为true,表示computed属性getter函数依赖的data值发生变化,但不调用观察者的get方法更新value值。再调用包含页面更新方法的观察者的update方法,在更新页面时会读取computed属性值,触发重定义的getter函数,此时由于computed属性的观察者dirty为true,调用该观察者的get方法,更新value值,并返回,完成页面的渲染。

5.dirty值初始为true,即首次读取computed属性值时,根据setter计算属性值,并保存在观察者value上,然后设置dirty值为false。之后读取computed属性值时,dirty值为false,不调用setter重新计算值,而是直接返回观察者的value,也就是上一次计算值。只有当computed属性setter函数依赖的data发生变化时,才设置dirty为true,即下一次读取computed属性值时调用setter重新计算。也就是说,computed属性依赖的data不发生变化时,不会调用setter函数重新计算值,而是读取上一次计算值。

JS中的事件顺序(事件捕获与冒泡)

上一篇

重新整理JavaScript知识点

下一篇

你也可能喜欢

评论已经被关闭。

插入图片

热门栏目

vue的computed实现原理

长按储存图像,分享给朋友