更新重新看了下源码

// Watcehr 的执行函数
get () {
pushTarget(this) // 将当前的Watcher放入队列
let value
const vm = this.vm
try {
value = this.getter.call(vm, vm)
} catch (e) {
if (this.user) {
handleError(e, vm, `getter for watcher "${this.expression}"`)
} else {
throw e
}
} finally {
// "touch" every property so they are all tracked as
// dependencies for deep watching
if (this.deep) {
traverse(value)
}
popTarget() // 将当前的Watcher从队列里清除
this.cleanupDeps()
}
return value
}

computed 属性如何做到依赖收集总结

初始化computed属性为lazy watcher this.value = this.lazy ? undefined: this.get(),lazy watcher 不会立即执行,此时Dep.target = null

当组件挂载时,会创建一个RenderWatcher,并且立即执行,此时Dep.target = RenderWatcher,这时data定义的每个属性都会收集RenderWatcher

当组件挂载时,如果模板里用到了某一个计算机属性,计算属性会执行自己的getter函数,dirty=true执行evaluate(),与此同时计算机属性所依赖的data属性收集该计算机属性对应watcher

此时 Dep.target = RenderWatcher,计算机属性收集RenderWatcher

所以计算机属性只有当其依赖的data属性时,才会被依赖收集watcher

<template>
<div>
a:{{ a }}
c:{{c}}
<p>b:{{ b }}</p>
<p>d:{{ d }}</p>
<button @click="a++">a++</button>
<button @click="c++">c++</button>
</div>
</template>
<script>
export default {
data() {
return {
a: 1,
c:1
};
},
computed: {
b(vm) {
return vm.a;
},
d() {
return 1;
}
}
};
</script> // b依赖a,a更新b更新,d不依赖任何响应式数据,始终返回1

以上更新2020-04-12

computed 初始化函数

const computedWatcherOptions = { lazy: true }

function initComputed (vm: Component, computed: Object) {
// $flow-disable-line
const watchers = vm._computedWatchers = Object.create(null)
// computed properties are just getters during SSR
const isSSR = isServerRendering() for (const key in computed) {
const userDef = computed[key]
const getter = typeof userDef === 'function' ? userDef : userDef.get
if (process.env.NODE_ENV !== 'production' && getter == null) {
warn(
`Getter is missing for computed property "${key}".`,
vm
)
} if (!isSSR) {
// create internal watcher for the computed property.
watchers[key] = new Watcher(
vm,
getter || noop,
noop,
computedWatcherOptions
)
}
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)
}
}
}
}

Vue会为每个computed属性创建一个lazy Watcher,在Watcher中有下面语句:

  this.dirty = this.lazy // for lazy watchers
this.value = this.lazy ? undefined: this.get() update () {
/* istanbul ignore else */
if (this.lazy) {
this.dirty = true
} else if (this.sync) {
this.run()
} else {
queueWatcher(this)
}
} evaluate () {
this.value = this.get()
this.dirty = false
}

computed 属性的getter

function createComputedGetter (key) {
return function computedGetter () {
const watcher = this._computedWatchers && this._computedWatchers[key]
if (watcher) {
if (watcher.dirty) {
watcher.evaluate()
}
if (Dep.target) {
watcher.depend()
}
return watcher.value
}
}
}

watcher.depend()表示在当前watcher添加依赖

watcher.dirty控制是否更新,依赖没改变就不会执行

computed定义函数

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)
}

总结:

  • 如果计算机属性定义后未使用,则依赖改变并不会执行
  • 计算机属性是Lazy的,只有在依赖更新的时候才会触犯返回新的值

【Vue2.x笔记2】从源码看computed对象的更多相关文章

  1. 【Vue2.x笔记3】从源码看watch对象

    初始化 function initWatch (vm: Component, watch: Object) { for (const key in watch) { const handler = w ...

  2. 解密随机数生成器(二)——从java源码看线性同余算法

    Random Java中的Random类生成的是伪随机数,使用的是48-bit的种子,然后调用一个linear congruential formula线性同余方程(Donald Knuth的编程艺术 ...

  3. memcached学习笔记——存储命令源码分析下篇

    上一篇回顾:<memcached学习笔记——存储命令源码分析上篇>通过分析memcached的存储命令源码的过程,了解了memcached如何解析文本命令和mencached的内存管理机制 ...

  4. [转]【安卓笔记】AsyncTask源码剖析

    [转][安卓笔记]AsyncTask源码剖析 http://blog.csdn.net/chdjj/article/details/39122547 前言: 初学AsyncTask时,就想研究下它的实 ...

  5. Laravel学习笔记之Session源码解析(上)

    说明:本文主要通过学习Laravel的session源码学习Laravel是如何设计session的,将自己的学习心得分享出来,希望对别人有所帮助.Laravel在web middleware中定义了 ...

  6. Hadoop学习笔记(10) ——搭建源码学习环境

    Hadoop学习笔记(10) ——搭建源码学习环境 上一章中,我们对整个hadoop的目录及源码目录有了一个初步的了解,接下来计划深入学习一下这头神象作品了.但是看代码用什么,难不成gedit?,单步 ...

  7. 从源码看Azkaban作业流下发过程

    上一篇零散地罗列了看源码时记录的一些类的信息,这篇完整介绍一个作业流在Azkaban中的执行过程,希望可以帮助刚刚接手Azkaban相关工作的开发.测试. 一.Azkaban简介 Azkaban作为开 ...

  8. memcached学习笔记——存储命令源码分析上篇

    原创文章,转载请标明,谢谢. 上一篇分析过memcached的连接模型,了解memcached是如何高效处理客户端连接,这一篇分析memcached源码中的process_update_command ...

  9. 从源码看Android中sqlite是怎么通过cursorwindow读DB的

    更多内容在这里查看 https://ahangchen.gitbooks.io/windy-afternoon/content/ 执行query 执行SQLiteDatabase类中query系列函数 ...

随机推荐

  1. NR / 5G - MAC Overview

  2. centos7.5下yum安装php-5.6.40(LNMP环境)

    cd /etc/yum.repos.d/ yum -y install epel-release #<===安装centos7下php5.6的epel和remi源 rpm -ivh http:/ ...

  3. 双向绑定Proxy VS Object.defineProperty

    Vue3.0的双向绑定将使用Proxy代替Object.defineProperty,据尤大说,速度提升了1倍. 本文我们来探讨一下Proxy对比Object.defineProperty究竟有哪些优 ...

  4. 来去学习之---KMP算法--next计算过程

    一.概述 KMP算法是一种字符串匹配算法,比如现有字符串 T:ABCDABCDABCDCABCDABCDE, P:ABCDABCDE P字符串对应的next值:[0,0,0,0,1,2,3,4,0] ...

  5. python len函数(41)

    在python中除了print函数之外,len函数和type函数应该算是使用最频繁的API了,操作都比较简单. 一.len函数简介 返回对象的长度(项目数)参数可以是序列(例如字符串str.元组tup ...

  6. Android埋点方案的简单实现-AOP之AspectJ

    个人博客 http://www.milovetingting.cn Android埋点方案的简单实现-AOP之AspectJ AOP的定义 AOP为Aspect Oriented Programmin ...

  7. 「数据挖掘入门系列」Python快速入门

    Python环境搭建 本次入门系列将使用Python作为开发语言.要使用Python语言,我们先来搭建Python开发平台.我们将基于Python 2.7版本.以及Python的开发发行版本Anaco ...

  8. MongoDB initial sync过程

    initial sync过程大致如下: (1)T1时间,从Primary同步所有数据库的数据,但不包括local的数据,复制时Mongo会扫描每个源数据库中的每个集合,并将所有数据插入对应的集合.通过 ...

  9. 令人抓狂的redis和rediscluster Python驱动包的安装

    本文环境:centos 7,Python3编译安装成功,包括pip3,然后需要安装redis相关的Python3驱动包,本的redis指redis包而非redis数据库,rediscluster类似. ...

  10. 9个常用的正则表达式-sunziren

    正数字:/^[1-9]{1}[0-9]*$|^0{1}\.{1}[0-9]+$|^[1-9]{1}[0-9]*\.{1}[0-9]+$/ 用户名:/^[a-z0-9_-]{3,16}$/ 密码:/^[ ...