博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Vue响应式原理-理解Observer、Dep、Watcher
阅读量:6904 次
发布时间:2019-06-27

本文共 3535 字,大约阅读时间需要 11 分钟。

开篇

最近在学习Vue的源码,看了网上一些大神的博客,看起来感觉还是蛮吃力的。自己记录一下学习的理解,希望能够达到简单易懂,不看源码也能理解的效果?

如果有错误,恳求大佬们指点嘿?

Object.defineProperty

相信很多同学或多或少都了解Vue的响应式原理是通过Object.defineProperty实现的。被Object.defineProperty绑定过的对象,会变成「响应式」化。也就是改变这个对象的时候会触发get和set事件。进而触发一些视图更新。举个栗子?

function defineReactive (obj, key, val) {    Object.defineProperty(obj, key, {        enumerable: true,        configurable: true,        get: () => {            console.log('我被读了,我要不要做点什么好?');            return val;        },        set: newVal => {            if (val === newVal) {                return;            }            val = newVal;            console.log("数据被改变了,我要把新的值渲染到页面上去!");        }    })}let data = {    text: 'hello world',};// 对data上的text属性进行绑定defineReactive(data, 'text', data.text);console.log(data.text); // 控制台输出 
<我被读了,我要不要做点什么好?>
data.text = 'hello Vue'; // 控制台输出
复制代码

Observer 「响应式」

Vue中用Observer类来管理上述响应式化Object.defineProperty的过程。我们可以用如下代码来描述,将this.data也就是我们在Vue代码中定义的data属性全部进行「响应式」绑定。

class Observer {    constructor() {        // 响应式绑定数据通过方法    	observe(this.data);    }}export function observe (data) {    const keys = Object.keys(data);    for (let i = 0; i < keys.length; i++) {       // 将data中我们定义的每个属性进行响应式绑定       defineReactive(obj, keys[i]);    }}复制代码

Dep 「依赖管理」

什么是依赖?

相信没有看过源码或者刚接触Dep这个词的同学都会比较懵。那Dep究竟是用来做什么的呢? 我们通过defineReactive方法将data中的数据进行响应式后,虽然可以监听到数据的变化了,那我们怎么处理通知视图就更新呢?

Dep就是帮我们收集【究竟要通知到哪里的】。比如下面的代码案例,我们发现,虽然data中有textmessage属性,但是只有message被渲染到页面上,至于text无论怎么变化都影响不到视图的展示,因此我们仅仅对message进行收集即可,可以避免一些无用的工作。

那这个时候messageDep就收集到了一个依赖,这个依赖就是用来管理datamessage变化的。

{

{message}}

复制代码
data: {    text: 'hello world',    message: 'hello vue',}复制代码

当使用watch属性时,也就是开发者自定义的监听某个data中属性的变化。比如监听message的变化,message变化时我们就要通知到watch这个钩子,让它去执行回调函数。

这个时候messageDep就收集到了两个依赖,第二个依赖就是用来管理watchmessage变化的。

watch: {    message: function (val, oldVal) {        console.log('new: %s, old: %s', val, oldVal)    },}        复制代码

当开发者自定义computed计算属性时,如下messageT属性,是依赖message的变化的。因此message变化时我们也要通知到computed,让它去执行回调函数。 这个时候messageDep就收集到了三个依赖,这个依赖就是用来管理computedmessage变化的。

computed: {    messageT() {        return this.message + '!';    }}复制代码

图示如下:一个属性可能有多个依赖,每个响应式数据都有一个Dep来管理它的依赖。

如何收集依赖

我们如何知道data中的某个属性被使用了,答案就是Object.defineProperty,因为读取某个属性就会触发get方法。可以将代码进行如下改造:

function defineReactive (obj, key, val) {    let Dep; // 依赖    Object.defineProperty(obj, key, {        enumerable: true,        configurable: true,        get: () => {            console.log('我被读了,我要不要做点什么好?');            // 被读取了,将这个依赖收集起来            Dep.depend(); // 本次新增            return val;        },        set: newVal => {            if (val === newVal) {                return;            }            val = newVal;            // 被改变了,通知依赖去更新            Dep.notify(); // 本次新增            console.log("数据被改变了,我要把新的值渲染到页面上去!");        }    })}复制代码

什么是依赖

那所谓的依赖究竟是什么呢?上面的图中已经暴露了答案,就是Watcher

Watcher 「中介」

Watcher就是类似中介的角色,比如message就有三个中介,当message变化,就通知这三个中介,他们就去执行各自需要做的变化。

Watcher能够控制自己属于哪个,是data中的属性的还是watch,或者是computedWatcher自己有统一的更新入口,只要你通知它,就会执行对应的更新方法。

因此我们可以推测出,Watcher必须要有的2个方法。一个就是通知变化,另一个就是被收集起来到Dep中去。

class Watcher {    addDep() {        // 我这个Watcher要被塞到Dep里去了~~    },    update() {        // Dep通知我更新呢~~    }, }复制代码

总结

回顾一下,Vue响应式原理的核心就是ObserverDepWatcher

Observer中进行响应式的绑定,在数据被读的时候,触发get方法,执行Dep来收集依赖,也就是收集Watcher

在数据被改的时候,触发set方法,通过对应的所有依赖(Watcher),去执行更新。比如watchcomputed就执行开发者自定义的回调方法。

本篇文章属于入门篇,能够先简单的理解ObserverDepWatcher三者的作用和关系。后面会逐渐详细和深入,循序渐进的理解和学习。

如果你觉得对你有帮助,就点个赞吧~

正在书写的系列~

欢迎交流~

转载于:https://juejin.im/post/5cf3cccee51d454fa33b1860

你可能感兴趣的文章
【素数筛】分解质因数
查看>>
【ADT】队列的基本C语言实现
查看>>
NYOJ-1057 寻找最大数(三)(贪心)
查看>>
【转】 [UnityUI]UGUI射线检测
查看>>
应用被强杀了怎么办
查看>>
jquery validate 插件使用心得
查看>>
Windows下安装mysql后,不知道root密码,如果修改root密码
查看>>
Linuxドライバ_LDD3メモ_ハードウェアとの通信
查看>>
数学之美系列四 -- 怎样度量信息?
查看>>
用Access+SharePoint 来收集数据
查看>>
Nginx 的 Location 配置指令块
查看>>
Spark小课堂Week5 Scala初探
查看>>
go练习1-翻转字符串
查看>>
java第一天学习笔记
查看>>
GPS定位为什么要转换处理?高德地图和百度地图坐标处理有什么不一样?
查看>>
冲刺博客 五
查看>>
poj 2389 大整数乘法
查看>>
JSON.stringify JSON.parse
查看>>
SQL语句学习
查看>>
用B表更新A表
查看>>