更新重新看了下源码

// 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. javascript json语句 与 js语句的互转

    //var data = "weihexin" //var data = ["weihexin", 1] var data = {name:"weih ...

  2. javascript 获取两点的像素距离

    getPosLen(sdot, edot){//获取2点距离 /* 56 40 56 40 00 40 56 40 56 */ return parseInt(Math.sqrt(Math.pow(M ...

  3. JavaScript将数组转换为链表

    JS中将数组转换为链表 /** * 将数组转换为链表 * @param array arr 需要转换的数组 * @param int type 转换的类型,0为单链表,1为循环链表 * @return ...

  4. linux下tar命令解压到指定的目录

    linux下tar命令解压到指定的目录 : #tar zxvf xx.tar.gz -C /xx//把根目录下的xx.tar.gz解压到/xx/下,前提要保证存在/xx这个目录 这个和cp命令有点不同 ...

  5. Android应用第一次启动时的欢迎界面制作

    原理是这样,我们在SharedPreferences中存储一个int型数据,用来代表第几次登录,每次启动时都读取出来判断是不是第一次启动,然后依次判断是否要显示欢迎界面, 具体实现如下: 设置一个欢迎 ...

  6. Demrystv

    Determined Energetic Motivated Reliable Yes Stick To Victory

  7. Ubuntu 系统连接到服务器

    Ubuntu 系统连接到服务器 我用的是 Ubuntu18.04 系统 假设你的服务器上的用户名是 root, 域名或者 ip 地址是 xyz 而且配置好了安全组(阿里云的)和云解析 首先要安装 op ...

  8. Python中关于日期的计算总结

    1.获取当前时间的两种方法: 代码如下: import datetime,timenow = time.strftime("%Y-%m-%d %H:%M:%S")print now ...

  9. Java与Go语言差异1 传值还是传引用

    在Java中,复杂类型(除原始类型外的其它类)作为入参,在方法中被修改后,跳出方法对象内的值仍会保持,也就是传的是引用.原始类型传的是值,如int, double等原始类型. Java代码: publ ...

  10. vue(六)--计算属性(computed)

    计算属性关键词: computed demo1: <div id="app"> <p>原始字符串: {{ message }}</p> < ...