Vue响应式原理-理解Observer、Dep、Watcher

栏目: 编程语言 · 发布时间: 5年前

内容简介:最近在学习Vue的源码,看了网上一些大神的博客,看起来感觉还是蛮吃力的。自己记录一下学习的理解,希望能够达到简单易懂,不看源码也能理解的效果:laughing:如果有错误,恳求大佬们指点嘿:yum:相信很多同学或多或少都了解Vue的响应式原理是通过

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

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

Object.defineProperty

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

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'; // 控制台输出 <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 变化的。

<div>
    <p>{{message}}</p>
</div>
复制代码
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 来管理它的依赖。

Vue响应式原理-理解Observer、Dep、Watcher

如何收集依赖

我们如何知道 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 三者的作用和关系。后面会逐渐详细和深入,循序渐进的理解和学习。

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

也可以来我的博客看看,最近在整理博客中... github博客


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Java编程思想

Java编程思想

埃克尔 / 机械工业出版社 / 2007-5-1 / 79.00元

《Java编程思想(英文版•第4版)》内容简介:特色:1.适合初学者与专业人员的经典的面向对象的叙述方式;为更新的Java SE5/6的相关内容增加了新的示例和章节。2.测验框架显示程序输出。3.设计模式贯穿于众多示例中:适配器、桥接器、职责链、命令、装饰器、外观、工厂方法、享元、点名、数据传输对象、空对象、代理、单例、状态、策略、模板方法以及访问者。4.为数据传输引入了XML;为用户界面引入了S......一起来看看 《Java编程思想》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具