【Vue2.x笔记2】从源码看computed对象
更新重新看了下源码
// 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对象的更多相关文章
- 【Vue2.x笔记3】从源码看watch对象
初始化 function initWatch (vm: Component, watch: Object) { for (const key in watch) { const handler = w ...
- 解密随机数生成器(二)——从java源码看线性同余算法
Random Java中的Random类生成的是伪随机数,使用的是48-bit的种子,然后调用一个linear congruential formula线性同余方程(Donald Knuth的编程艺术 ...
- memcached学习笔记——存储命令源码分析下篇
上一篇回顾:<memcached学习笔记——存储命令源码分析上篇>通过分析memcached的存储命令源码的过程,了解了memcached如何解析文本命令和mencached的内存管理机制 ...
- [转]【安卓笔记】AsyncTask源码剖析
[转][安卓笔记]AsyncTask源码剖析 http://blog.csdn.net/chdjj/article/details/39122547 前言: 初学AsyncTask时,就想研究下它的实 ...
- Laravel学习笔记之Session源码解析(上)
说明:本文主要通过学习Laravel的session源码学习Laravel是如何设计session的,将自己的学习心得分享出来,希望对别人有所帮助.Laravel在web middleware中定义了 ...
- Hadoop学习笔记(10) ——搭建源码学习环境
Hadoop学习笔记(10) ——搭建源码学习环境 上一章中,我们对整个hadoop的目录及源码目录有了一个初步的了解,接下来计划深入学习一下这头神象作品了.但是看代码用什么,难不成gedit?,单步 ...
- 从源码看Azkaban作业流下发过程
上一篇零散地罗列了看源码时记录的一些类的信息,这篇完整介绍一个作业流在Azkaban中的执行过程,希望可以帮助刚刚接手Azkaban相关工作的开发.测试. 一.Azkaban简介 Azkaban作为开 ...
- memcached学习笔记——存储命令源码分析上篇
原创文章,转载请标明,谢谢. 上一篇分析过memcached的连接模型,了解memcached是如何高效处理客户端连接,这一篇分析memcached源码中的process_update_command ...
- 从源码看Android中sqlite是怎么通过cursorwindow读DB的
更多内容在这里查看 https://ahangchen.gitbooks.io/windy-afternoon/content/ 执行query 执行SQLiteDatabase类中query系列函数 ...
随机推荐
- 带你简单了解域名系统DNS
带你简单了解域名系统DNS 一.域名简介 1.1.DNS服务的作用 负责解析域名,将域名解析成IP地址. 1.2.域名系统概述 由于32位的IP地址并不容易记忆,人们往往喜欢记忆网站的域名.所以当我们 ...
- [Effective Java 读书笔记] 第三章类和接口 第十八--十九条
十八条 接口优于抽象类 接口的特点: 1.一个类可以实现多个接口,不能继承多个类(抽象类) 2.接口不能有具体的方法实现,只定义标准类型 骨架类: 即实现一个abstract类来实现接口,提供给其他类 ...
- JAVA SOCKET多线程等待接受客户端信息实现
服务端程序: public class Demo { public static void main(String[] args) { // TODO 自动生成的方法存根 try { ServerSo ...
- Hexo搭建静态博客踩坑日记(一)
前言 博客折腾一次就好, 找一个适合自己的博客平台, 专注于内容进行提升. 方式一: 自己买服务器, 域名, 写前端, 后端(前后分离最折腾, 不分离还好一点)... 方式二: 利用Hexo, Hug ...
- mysql 8.0.12版本 忘记密码
1.mysqld --console --skip-grant-tables --shared-memory 2.另一个控制台 mysq 3.use mysql; 4.select user,host ...
- LVM知识梳理
1 LVM介绍 LVM即logical volume manager逻辑卷管理,其主要特点是:可以动态地扩大和缩小分区大小,但前提是分区的文件系统必须是LVM格式的,lvm的实现需要安装lvm2软件包 ...
- FTP服务器配置http访问(配置nginx+ftp服务器)
一.搭建nginx服务器 先安装nginx服务器 # yum install nginx -y 启动nginx服务 # systemctl start nginx 浏览器访问:http://192.1 ...
- KVM管理工具webvirtmgr的使用
WebVirtMgr的日常配置:添加宿主机,创建虚拟机,磁盘扩容,快照等具体操作记录如下: 一.创建虚拟机 1.创建存储池 点击创建的宿主机,进入虚拟机部署界面 点击“存储池”按钮,创建存储池(即创建 ...
- MySQL命令随手记之alter
修改表名 alter table 表名 rename 新表名; //修改table名 添加.删除.修改字段 alter table 表名 add [column] 列名 数据类型; //添加colum ...
- http报文解析
http报文结构 报文首部 起始行 请求报文的起始行: 方法(method) request-URL version(http协议版本) 响应报文的起始行 HTTP响应码 请求头 通用首部 请求首部 ...