Vue 源码解读(4)—— 异步更新

前言

上一篇的 Vue 源码解读(3)—— 响应式原理 说到通过 Object.defineProperty 为对象的每个 key 设置 getter、setter,从而拦截对数据的访问和设置。

当对数据进行更新操作时,比如 obj.key = 'new val' 就会触发 setter 的拦截,从而检测新值和旧值是否相等,如果相等什么也不做,如果不相等,则更新值,然后由 dep 通知 watcher 进行更新。所以,异步更新 的入口点就是 setter 中最后调用的 dep.notify() 方法。

目的

  • 深入理解 Vue 的异步更新机制

  • nextTick 的原理

源码解读

dep.notify

/src/core/observer/dep.js

/**
 * 通知 dep 中的所有 watcher,执行 watcher.update() 方法
 */
notify () {
  // stabilize the subscriber list first
  const subs = this.subs.slice()
  // 遍历 dep 中存储的 watcher,执行 watcher.update()
  for (let i = 0, l = subs.length; i < l; i++) {
    subs[i].update()
  }
} 

watcher.update

/src/core/observer/watcher.js

/**
 * 根据 watcher 配置项,决定接下来怎么走,一般是 queueWatcher
 */
update () {
  /* istanbul ignore else */
  if (this.lazy) {
    // 懒执行时走这里,比如 computed
    // 将 dirty 置为 true,可以让 computedGetter 执行时重新计算 computed 回调函数的执行结果
    this.dirty = true
  } else if (this.sync) {
    // 同步执行,在使用 vm.$watch 或者 watch 选项时可以传一个 sync 选项,
    // 当为 true 时在数据更新时该 watcher 就不走异步更新队列,直接执行 this.run 
    // 方法进行更新
    // 这个属性在官方文档中没有出现
    this.run()
  } else {
    // 更新时一般都这里,将 watcher 放入 watcher 队列
    queueWatcher(this)
  }
} 

queueWatcher

/src/core/observer/scheduler.js

/**
 * 将 watcher 放入 watcher 队列 
 */
export function queueWatcher (watcher: Watcher) {
  const id = watcher.id
  // 如果 watcher 已经存在,则跳过,不会重复入队
  if (has[id] == null) {
    // 缓存 watcher.id,用于判断 watcher 是否已经入队
    has[id] = true
    if (!flushing) {
      // 当前没有处于刷新队列状态,watcher 直接入队
      queue.push(watcher)
    } else {
      // 已经在刷新队列了
      // 从队列末尾开始倒序遍历,根据当前 watcher.id 找到它大于的 watcher.id 的位置,然后将自己插入到该位置之后的下一个位置
      // 即将当前 watcher 放入已排序的队列中,且队列仍是有序的
      let i = queue.length - 1
      while (i > index && queue[i].id > watcher.id) {
        i--
      }
      queue.splice(i + 1, 0, watcher)
    }
    // queue the flush
    if (!waiting) {
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值