说说Vue的几个watcher(二)——computed watcher
2020/4/16 11:08:03
本文主要是介绍说说Vue的几个watcher(二)——computed watcher,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
为降低心智负担,本文只做原理和流程的分析,尽量不涉及Vue.js源码。
如果想要看结合源码的分析,建议猛戳这里:《Vue 的计算属性真的会缓存吗?(保姆级教学,原理深入揭秘)》。这篇是我看过的最好的Vue.js原理分析文章,没有之一。
作者写的所有Vue.js原理解析文章都非常好,建议大家都能阅读一下并关注作者(与我利益无关,与大家利益相关啊)
watcher系列文章在此,本篇是第二篇
- 说说Vue的几个watcher(一)——render watcher
- 说说Vue的几个watcher(二)——computed watcher
- 说说Vue的几个watcher(二)——普通watcher(待续...)
使用场景
computed属性值一般可以用在哪些地方呢?我们说两个常用简单例子
- 示例1:模板里
export default { template: '<div>My name is {{ fullname }}</div>', data () { return { firstName: 'Steve', lastName: 'Jobs' } }, computed: { fullName: ({ firstName, lastName }) => `${firstName}·${lastName}` } } 复制代码
- 示例2:模板、以及其他计算属性里
export default { template: '<div>{{ selfIntroduction }}</div>', data () { return { firstName: 'Steve', lastName: 'Jobs' } }, computed: { fullName: ({ firstName, lastName }) => `${firstName}·${lastName}`, selfIntroduction: ({ fullName }) => `My name is ${fullName}` } } 复制代码
建立联系
看过了上面的使用场景,我们应该提出的问题是:
- data属性值变了,computed属性怎么知道?
- computed的属性值变了,模板渲染函数怎么知道?
经过了上节render-watcher的介绍,我们应该有了一个大概的思路:
- 得为computed属性创建watcher(正是computed-watcher),并添加到相关data属性值的订阅者队列里。watcher的回调函数正是computed属性值(函数)
- computed属性值的变化是由data属性变化引起的。因此若想模板也跟着变化,render-watcher就得添加到computed属性的相关data的订阅者队列里。
有点绕?对照上面代码示例1来看,就是render-watcher得添加到firstName
和lastName
的订阅者队列里
下面我们来看看怎么建立这个联系
依赖收集
computed属性的初始化
首先要对computed属性进行初始化。
当完成所有data属性值的访问劫持劫持之后,便进入了computed属性的初始化流程:
- 遍历computed属性,为每个computed属性都创建一个watcher;
- 遍历computed属性,对每个computed属性进行get劫持
其中get劫持是最关键的步骤。在这个环节里,实现了我们上面提出的解决方案:
- 将computed-watcher添加到data属性值的订阅者队列。
- 将render-watcher添加到data属性值的订阅者队列。
这样就能实现,当data属性值变化后:
- render函数执行
- computed属性函数执行并返回新执行结果
我们来看看具体是怎么实现的:
computed属性的get劫持
齿轮从render函数被执行开始转起。
render函数执行时,触发了computed属性值的get。
接着,在get里依序发生了这么几件事:
-
执行computed属性函数,将函数返回值保存起来
注意,执行computed函数的过程中,data属性值被get了。
-
data属性值把当前的computed属性的watcher添加到订阅队列里
-
data属性值把render-watcher添加到订阅队列里
-
返回保存起来的computed函数执行结果
注意订阅队列里的顺序,computed-watcher先,render-watcher后。
好了,齿轮的第一次运转结束了。
连携反应
模板直接引用computed属性
data的属性值被改变了。比如我们修改示例1中的lastName
属性:this.lastName = 'Nash'
好了,这个时候会发生什么?
没错,齿轮又一次运转了起来。
- data的属性值被set了
- data属性值通知所有订阅者,你们要更新了
- computed-watcher执行computed属性函数,返回了新的值
- render-watcher执行render回调函数,渲染了新的视图
逻辑好的读者可能已经开始起疑了:
computed-watcher回调执行了一次computed函数,render-watcher回调render函数,会触发computed属性的get进而又执行了computed函数,这不是重复执行了两次?
说的对!这么干不行!我们只能挑一个watcher,在其回调里触发computed函数的执行。这么做:
- 在computed-watcher的回调中,我们将computed属性标记为“待更新“
- 在render-watcher→render函数→computed属性值被get时,看有没有”待更新“标记,有就执行computed函数,执行完了就取消掉“待更新”标记。没有就直接返回上次执行后保存下来的结果
抽出上面的核心逻辑,用伪代码表示一下:
// dirty就是数据该更新了 if (dirty) { setComputedValueCache(update()) dirty = false } return getComputedValueCache() 复制代码
一言蔽之,每次都返回缓存值。无非是返回前更不更新这个缓存值而已。
到这里,我们已经弄清楚,在模板里使用computed属性值时,是如何做到响应式的了;也弄清楚computed-watcher是什么、干什么用、怎么用了。
事已至此,顺手梳理一下上面示例2的情况,即:当computed属性引用了computed属性时,会发生什么?
模板间接引用computed属性
什么是间接引用computed属性?看上面示例2就知道,引用链如下:
模板 → computed属性1 → computed属性2 → data属性值
computed属性2就是模板的间接引用。
经过上文,想必我们已经不必再从头开始分析了(肝不动了😂😂😂)。直接看data属性值最后的订阅队列:
data属性值→ [computed-watcher1, computed-watcher2, render-watcher]。
data属性值被set的时候,computed-watcher1、computed-watcher2相继被标记“待更新”;待到render-watcher更新时,就会依序执行:
- render函数
- computed1属性被get
- computed1属性函数执行
- computed2属性被get
- computed2属性函数执行
- 缓存并返回computed2结果给computed1
- 缓存并返回computed1结果给render函数
- render函数将computed1新值渲染到视图中
至此,我们就可以对computed-watcher有了最基本、最简单的认识了。
这篇关于说说Vue的几个watcher(二)——computed watcher的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-10-04package.json 文件位置在哪?-icode9专业技术文章分享
- 2024-10-01Craco.js学习:从入门到实践指南
- 2024-10-01Create-React-App学习:入门与实践指南
- 2024-10-01CSS-in-JS学习:从入门到实践指南
- 2024-09-30JSX语法学习:从入门到初步掌握
- 2024-09-30Mock.js学习:入门教程与实战演练
- 2024-09-30React Hooks学习:从入门到实践
- 2024-09-30受控组件学习:React中的基础入门教程
- 2024-09-29JS定时器教程:初学者必看指南
- 2024-09-29JS对象教程:初学者的全面指南