zoukankan      html  css  js  c++  java
  • ② 响应式系统的依赖收集追踪原理

    1 为什么要依赖收集?

    栗子

    1. new 一个 Vue 实例
    new Vue({
        template: `
        	<div>
        		<span>{{ text1 }}</span>
        		<span>{{ text2 }}</span>
        	</div>
        `,
        data: {
            text1: 'text1',
            text2: 'text2',
            text3: 'text3'
        }
    })
    
    2. 执行操作 this.text3 = "modify text3"

    因为视图并不需要用到 text3,所以我们并不需要触发 cb 函数来更新视图

    栗子

    1. 在多个 Vue 实例中用到同一个对象(全局对象)
    let globalObj = {
        text1: 'text1'
    };
    let o1 = new Vue({
        template: `
        	<div>
        		<span>{{ text1 }}</span>
        	</div>
        `,
        data: globalObj
    });
    let o2 = new Vue({
        template: `
        	<div>
        		<span>{{ text1 }}</span>
        	</div>
        `,
        data: globalObj
    });
    
    2. 执行操作 globalObj.text1 = 'hello text1'

    依赖收集会让 text1 这个数据知道需要通知 o1 和 o2 两个 Vue 实例进行视图的更新

    • 形成数据与视图的一种对应关系

    2 如何实现依赖收集?

    2.1 订阅者 Dep

    实现订阅者 Dep:用来存放 Watcher 观察者对象

    addSub 方法可以在目前的 Dep 对象中增加一个 Watcher 的订阅操作
    notify 方法通知目前 Dep 对象的 subs 中的所有 Watcher 对象触发更新操作

    class Dep {
        constructor () {
            // 用来存放Watcher对象的数组
            this.subs = [];
        }
        // 在subs中添加一个Watcher对象
        addSub (sub) {
            this.subs.push(sub);
        }
        // 通知所有Watcher对象更新视图
        notify () {
            this.subs.forEach(sub => {
                sub.update();
            })
        }
    }
    

    2.2 观察者 Watcher

    class Watcher {
        constructor () {
            // 在new一个Watcher对象时将该对象赋值给Dep.target,在get中会用到
            Dep.targer = this;
        }
        // 更新视图的方法
        update () {
            console.log('视图更新啦~');
        }
    }
    Dep.target = null;
    

    2.3 依赖收集

    修改 defineReactive 以及 Vue 的构造函数
    增加 Dep 类,用来收集 Watcher对象
    • 在对象被 时,会触发 reactiveGetter 方法把当前的 Watcher 对象(存放在 Dep.target 中)收集到 Dep 类中去

    • 当该对象被 时,会触发 reactiveSetter 方法,通知 Dep 类调用 notify 来触发所有 Watcher 对象的 update 方法更新对应视图

    function defineReactive (obj, key, val) {
    	// Dep类对象
    	const dep = new Dep();
        Object.defineProperty(obj, key, {
            enumberable: true,
            configurable: true,
            get: function reactiveGetter () {
                // 将Dep.target(当前Watcher对象)存入dep的subs中
                dep.addSubs(Dep.target);
                return val;
            },
            set: function reactiveSetter (newVal) {
                if (newVal === val) return;
                // 在set时触发dep的notify来通知所有的Watcher对象更新视图
                dep.notify();
            } 
        })
    }
    
    class Vue {
        // Vue构造类
        constructor (options) {
            this._data = options.data;
            // 新建一个Watcher观察者对象,此时Dep.target会指向这个Watcher对象
            new Watcher();
            // 模仿render的过程,为了触发test属性的get函数
            console.log('render~', this._data.test)
        }
    }
    

    总结

    1. observer 的过程会注册 get 方法,用来进行依赖收集
    2. 该闭包 observer 中会有一个 Dep 对象,用来存放 Watcher 对象的实例

    3 Object.defineProperty 的set/get方法所处理的事情:

    • 依赖收集的过程就是把 Watcher 实例存放到对应的 Dep 对象中,get 方法可以让当前的 Watcher 对象(Dep.target)存放到它的 subs 中(addSub),在数据变化时,set 会调用 Dep 对象的 notify 方法通知它内部所有的 Watcher 对象进行视图更新。

    依赖收集的前提条件

    1. 触发 get 方法

    2. 新建一个 Watcher 对象

  • 相关阅读:
    razor在App_Code中使用ActionLink无效的解决方案
    科技的进步会给人带来幸福么?
    C6000系列之C6455 DSP的EMIFA接口
    C6000系列之C6455DSP的GPIO模块
    C语言文件操作与例子
    C语言中fscanf函数读取double型浮点数的问题
    MATLAB读取CCS保存的数据
    CCS 3.3 操作C函数读写文件
    复数矩阵乘法C语言实现
    C6000系列之C6455DSP的中断系统
  • 原文地址:https://www.cnblogs.com/pleaseAnswer/p/14331187.html
Copyright © 2011-2022 走看看