Vue响应式原理部分源码分析(一)

本文深入解析了Vue.js中Dep和Watcher的角色和交互。Dep是收集watcher的数组,用于管理订阅者,提供addSub、removeSub和depend方法。Watcher则是表达式变化的监听者,负责收集依赖并响应变化。当数据变化时,通过Dep通知相关Watcher更新视图。同步情况下,notify方法按watcher的id顺序进行更新。
摘要由CSDN通过智能技术生成

首先基于我的理解分析Dep构造函数

  /**
   * Remove an item from an array.
   */
  function remove (arr, item) {
    if (arr.length) {
      var index = arr.indexOf(item);
      if (index > -1) {
        return arr.splice(index, 1)
      }
    }
  }

以上是Dep的原型方法中removeSub部分用到的函数。remove函数接收两个参数,数组和元素。逻辑就是数组中存在这个元素,就将它移除,并封装成数组返回。

  // The current target watcher being evaluated.
  // This is globally unique because only one watcher
  // can be evaluated at a time.
  Dep.target = null;
  var targetStack = [];

  function pushTarget (target) {
    targetStack.push(target);
    Dep.target = target;
  }

  function popTarget () {
    targetStack.pop();
    Dep.target = targetStack[targetStack.length - 1];
  }

以上Dep的原型方法中depend用到的Dep.target。看作者注释,目前正在被评估的目标watcher,这在作用域范围内是独一无二的,因为同一时刻只有一个watcher能被评估。 所以Dep.target是啥,就是现在在评估的watcher。targetStack是一个栈,pushTarget和popTarget就是实现栈的方法,Dep.target对应的就是栈顶的watcher。还有一个点,是Dep.target用的的API addDep。

  /**
   * Add a dependency to this directive.
   */
  Watcher.prototype.addDep = function addDep (dep) {
    var id = dep.id;
    if (!this.newDepIds.has(id)) {
      this.newDepIds.add(id);
      this.newDeps.push(dep);
      if (!this.depIds.has(id)) {
        dep.addSub(this);
      }
    }
  };

由以上可以看出,这个API是watcher原型链上的方法。看作者的注释, 向这个watcher添加依赖。watcher的分析不在本文内,以后找时间分析。

  /**
   * A dep is an observable that can have multiple
   * directives subscribing to it.
   */
  var Dep = function Dep () {
    this.id = uid++;
    this.subs = [];
  };

  Dep.prototype.addSub = function addSub (sub) {
    this.subs.push(sub);
  };

  Dep.prototype.removeSub = function removeSub (sub) {
    remove(this.subs, sub);
  };

  Dep.prototype.depend = function depend () {
    if (Dep.target) {
      Dep.target.addDep(this);
    }
  };

  Dep.prototype.notify = function notify () {
    // stabilize the subscriber list first
    var subs = this.subs.slice();
    if (!config.async) {
      // subs aren't sorted in scheduler if not running async
      // we need to sort them now to make sure they fire in correct
      // order
      subs.sort(function (a, b) { return a.id - b.id; });
    }
    for (var i = 0, l = subs.length; i < l; i++) {
      subs[i].update();
    }
  };

首先看作者注释,dep是一个可被观测的对象,可以有多个watcher去订阅它。所以dep是什么,dep是收集watcher的数组,并在原型上定义了对watcher进行管理的一组方法。那么什么是watcher?在Vue1.0中,它具有细粒度的特征,当数据发生改变时,通知到每一个用到数据的地方,那么,就会在一定程度上对性能造成影响。在Vue2.0后,作者采用了中等粒度的设计方式,当数据发生改变时,通知到watcher,再由watcher通知到具体关联的依赖集体。

/**
 * A watcher parses an expression, collects dependencies,
 * and fires callback when the expression value changes.
 * This is used for both the $watch() api and directives.
 * /

以上是watcher的注释的意思是watcher是一个订阅者,收集依赖(collects dependences),并且在表达式发生变化时触发回调,这个逻辑同时适用于$watch api以及指令。什么是依赖,我的理解是具体用到数据的地方。

经由上面的分析,dep是什么,dep的addSub、removeSub以及depend方法是干啥的就已经很清楚了。dep是收集watcher的数组,是一个订阅者列表,addSub是把watcher压入数组,removeSub是移除指定的watcher,而depend就是修改watcher(这一部分需要看watcher api的源码,不在本文讨论范围内)。再来看notify是干啥的。

    if (!config.async) {
      // subs aren't sorted in scheduler if not running async
      // we need to sort them now to make sure they fire in correct
      // order
      subs.sort(function (a, b) { return a.id - b.id; });
    }

以上作者考虑到了同步的场景,在同步的情况下以watcher的id进行排序。也就是说在同步的情况下以watcher的id顺序进行通知。(为什么要这样做,正在思考中)所以notify是干啥的,它是通知watcher更新的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值