Vue源码解析——响应式原理(Dep收集依赖)

概述

  • 本文是解析Vue的响应式原理。在Vue2.0中,数据的代理是用使用Object.difineProperty实现,但这只是响应式原理的部分。在源码中,还涉及到Dep、Watcher这两个类,负责收集依赖、创建订观察者。
  • Dep的功能是收集依赖,具体指某个变量在哪些地方用到了,如HTML页面、computed、watch中。当这个变量变化后,使用到这个变量的所有地方都会重新更新。
  • Watcher:观察者,表示使用到某个变量的地方,有地方用到了就创建观察者。当某个变量重新赋值后,触发Dep通知更新时,该变量的观察者们全部重新执行,之后再通过渲染更新到页面中。

Dep类简介

  • 该类有提供depend方法(表示添加订阅者)、notify方法(通知订阅者们更新)、subs属性(表示订阅者)
  • subs是一个数组,里面存放Watcher实例,表示哪些地方用到了指定的代理数据
  • 有兴趣的同学可以看源码dep.js

Watcher简介

  • 该类有提供addDep(添加到Dep中,收集依赖)
  • 有兴趣的同学可以看源码watcher.js

调试代码实现——模拟整个流程

  • 构造DepClass、Wacher
  • 代理数据,下面代码中代理“num”数据举例
  • 模拟页面使用num的场景(比如实际开发中展示num属性值),出发Dep类收集依赖(depend方法)。
  • num重新赋值,触发Dep通知订阅者(subs属性)更新
  • 流程图示

image.png

    const proxyObj = {}; // 代理对象
    const originObj = { // 元数据
      num: 20, // 
    };

    // 创建Dep类
    class DepClass {
      subs = []; // 订阅者
      target = null;

      addSub(sub) {
        this.subs.push(sub);
        console.log("--sss", this.subs);
      }

      depend() {
        console.log("dep类收集依赖---");

        if (this.target) {
          this.target.addDep(this);
        }
      }

      notify() {
        console.log("执行notify -> 通知订阅们 -> 重新执行", this.subs);

        this.subs.forEach((sub) => sub.run());
      }
    }

    // 创建Watcher类
    class Wacher {
      run() { // 要执行更新的主体
        console.log("更新内容");
      }
      addDep(dep) {
         // 这里的this表示当前的Watcher实例
        dep.addSub(this);
      }
    }

    // 收集某个key 的依赖——页面上哪些地方用到了
    const dep = new DepClass();
    dep.target = new Wacher();

    Object.defineProperty(proxyObj, "num", {
      get() {
        dep.depend(); // 获取一次“num”值,Dep就添加一次依赖
        return originObj.num;
      },
      set(newValue) {
        dep.notify(); // 重新赋值一次,就通知订阅者重新更新(添加的Watcher重新计算)
        
        return (originObj.num = newValue);
      },
    });

    // 调试代码
    console.log(proxyObj.num); // 模拟页面中哪些地方用到了代理的Key
    proxyObj.num = 39; // 重新复制后,dep通知订阅者们重新执行
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享