当数据发生变化的时候,触发 setter 逻辑,把在依赖过程中订阅的所有观察者,也就是 watcher 都触发他们的 update 过程,这个过程又利用了队列做了进一步的优化,在 nextTick 后执行所有 watcher 的 run,最后执行他们的回调函数 代码块 defineReactive dep.notify() subs.update(); queueWatcher flushSche…

当数据发生变化的时候,触发 setter 逻辑,把在依赖过程中订阅的所有观察者,也就是 watcher 都触发他们的 update 过程,这个过程又利用了队列做了进一步的优化,在 nextTick 后执行所有 watcher 的 run,最后执行他们的回调函数

代码块

  1. defineReactive
// src/core/observer/index.js
export function defineReactive(obj: Object, key: string, val: any, customSetter?: ?Function, shallow?: boolean) {
  const dep = new Dep();

  const property = Object.getOwnPropertyDescriptor(obj, key);
  if (property && property.configurable === false) {
    return;
  }

  // cater for pre-defined getter/setters
  const getter = property && property.get;
  const setter = property && property.set;
  if ((!getter || setter) && arguments.length === 2) {
    val = obj[key];
  }

  let childOb = !shallow && observe(val);
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    // ...
    set: function reactiveSetter(newVal) {
      const value = getter ? getter.call(obj) : val;
      /* eslint-disable no-self-compare */
      if (newVal === value || (newVal !== newVal && value !== value)) {
        return;
      }
      /* eslint-enable no-self-compare */
      if (process.env.NODE_ENV !== 'production' && customSetter) {
        customSetter();
      }
      if (setter) {
        setter.call(obj, newVal);
      } else {
        val = newVal;
      }
      // shallow为false的时候,会把新设置的值编程一个响应式对象
      childOb = !shallow && observe(newVal);
      // 通知所有订阅者
      dep.notify();
    }
  });
}
  1. dep.notify()
// src/core/observer/dep.js
class Dep {
  // ...
  notify() {
    const subs = this.subs.slice();
    // 遍历所有subs,subs就是Watcher实例数组
    for (let i = 0, l = subs.length; i < l; i++) {
      // 然后调用每一个watcher的update方法
      subs[i].update();
    }
  }
}
  1. subs.update();
// src/core/observer/watcher.js
class Watcher {
  // ...
  update() {
    // 针对watcher状态,会执行不同的逻辑
    // 针对计算属性
    if (this.computed) {
      // A computed property watcher has two modes: lazy and activated.
      // It initializes as lazy by default, and only becomes activated when
      // it is depended on by at least one subscriber, which is typically
      // another computed property or a component's render function.
      if (this.dep.subs.length === 0) {
        // In lazy mode, we don't want to perform computations until necessary,
        // so we simply mark the watcher as dirty. The actual computation is
        // performed just-in-time in this.evaluate() when the computed property
        // is accessed.
        this.dirty = true;
      } else {
        // In activated mode, we want to proactively perform the computation
        // but only notify our subscribers when the value has indeed changed.
        this.getAndInvoke(() => {
          this.dep.notify();
        });
      }
      // 针对同步watcher的时候
    } else if (this.sync) {
      this.run();
    } else {
      // 一般组件更新的场景,都会走到这个逻辑
      queueWatcher(this);
    }
  }
}
  1. queueWatcher
// src/core/observer/scheduler.js
const queue: Array<Watcher> = [];
let has: { [key: number]: ?true } = {};
let waiting = false;
let flushing = false;
// Vue在做派发更新的时候会做一个优化,并不会每次数据改变的时候都触发watcher的回调,
// 而是把这些watcher先添加到一个队列中,然后在nextTick后执行flushSchedulerQueue
export function queueWatcher(watcher: Watcher) {
  const id = watcher.id;
  // 首先用has对象保证同一个watcher只添加一次
  if (has[id] == null) {
    has[id] = true;
    // 接着对flushing进行判断
    if (!flushing) {
      queue.push(watcher);
    } else {
      let i = queue.length - 1;
      // 找到第一个待插入的watcher的id比当前队列中的watcher的id大的位置
      while (i > index && queue[i].id > watcher.id) {
        i--;
      }
      // 把watcher按照id插入队列,因为queue的长度发生变化
      queue.splice(i + 1, 0, watcher);
    }
    // 通过wating保证nextTick(flushSchedulerQueue)只调用一次
    if (!waiting) {
      waiting = true;
      // 执行完毕后flushing为true,继续执行queueWatcher
      nextTick(flushSchedulerQueue);
    }
  }
}
  1. flushSchedulerQueue

    三个过程:1、队列排序,2、队列遍历 3、状态恢复

// src/core/observer/scheduler.js
let flushing = false;
let index = 0;
// 执行完毕后,flushing为true
function flushSchedulerQueue() {
  flushing = true;
  let watcher, id;
  // 队列排序
  // 先对队列做了从小到大的排序
  // 1.组件更新由父到子,父组件创建过程是优先于子组件的,所以watcher的创建也是先父后子,执行顺序也是先父后子
  // 2.用户自定义的watcher要优先于渲染watcher执行,因为用户自定义watcher是在渲染watcher之前创建的
  // 3.如果一个组件在父组件的watcher执行期间被销毁,那么它对应的watcher执行都可以被跳过,所以父组件的watcher先执行
  queue.sort((a, b) => a.id - b.id);
  // 队列遍历
  // 每次遍历的时候都要重新计算queue的长度,因为很可能在run的过程中再次添加新的watcher
  for (index = 0; index < queue.length; index++) {
    watcher = queue[index];
    if (watcher.before) {
      watcher.before();
    }
    id = watcher.id;
    has[id] = null;
    // 因为很可能在run的过程中再次添加新的watcher,添加新的watcher就会再次执行queueWatcher
    watcher.run();
    // 判断是否无限循环更新,watcher.run()可能执行queueWatcher
    if (process.env.NODE_ENV !== 'production' && has[id] != null) {
      circular[id] = (circular[id] || 0) + 1;
      if (circular[id] > MAX_UPDATE_COUNT) {
        warn('You may have an infinite update loop ' + (watcher.user ? `in watcher with expression "${watcher.expression}"` : `in a component render function.`), watcher.vm);
        break;
      }
    }
  }

  // keep copies of post queues before resetting state
  const activatedQueue = activatedChildren.slice();
  const updatedQueue = queue.slice();
  // 状态恢复
  resetSchedulerState();

  // call component updated and activated hooks
  callActivatedHooks(activatedQueue);
  callUpdatedHooks(updatedQueue);

  // devtool hook
  /* istanbul ignore if */
  if (devtools && config.devtools) {
    devtools.emit('flush');
  }
}
  1. resetSchedulerState
const queue: Array<Watcher> = [];
let has: { [key: number]: ?true } = {};
let circular: { [key: number]: number } = {};
let waiting = false;
let flushing = false;
let index = 0;
// 把这些控制流程状态的一些变量恢复到初始值,把watcher队列清空
function resetSchedulerState() {
  index = queue.length = activatedChildren.length = 0;
  has = {};
  if (process.env.NODE_ENV !== 'production') {
    circular = {};
  }
  waiting = flushing = false;
}
  1. watcher.run()
class Watcher {
  // run函数实际上是执行this.getAndInvoke(this.cb)方法,并传入watcher回调函数
  run() {
    if (this.active) {
      this.getAndInvoke(this.cb);
    }
  }
  getAndInvoke(cb: Function) {
    // 执行this.get()方法求值
    // 对于渲染watcher来说,执行this.get()方法求值的时候,会执行getter方法
    // updateComponent = () => {
    //   vm._update(vm._render(), hydrating);
    // };
    // 这就是当我们去修改组件的响应式数据的时候,就会触发组件的重新渲染的原因,然后就执行patch过程
    const value = this.get();
    if (
      // 如果新旧值不等或者新值是对象或是deep模式
      value !== this.value ||
      // Deep watchers and watchers on Object/Arrays should fire even
      // when the value is the same, because the value may
      // have mutated.
      isObject(value) ||
      this.deep
    ) {
      // 会执行watcher的回调,
      const oldValue = this.value;
      this.value = value;
      this.dirty = false;
      if (this.user) {
        try {
          // 回调执行的时候会把第一个和第二个参数传入新value,和旧值oldValue
          // 这就是为什么当添加自定义watcher的时候能在回调函数的参数中拿到新旧值的原因
          cb.call(this.vm, value, oldValue);
        } catch (e) {
          handleError(e, this.vm, `callback for watcher "${this.expression}"`);
        }
      } else {
        cb.call(this.vm, value, oldValue);
      }
    }
  }
}

暂无评论