# $nextTick

  • 通过异步任务来优化一次同步任务中触发的多次setter
  • 优先度Promise.then() > new MutationObserver()> setImmediate() > setTimeout()

# queueWatcher

  • 当数据发生改变时(触发setter),会通知相对应的dep.subs[]里的所有Wathcer更新
  • 当一个未设置sync的Wathcer更新时 会将Wathcer添加到异步队列queueWathcer(this)中。
  • 将当前同步任务中所有触发的 Wathcer 放在异步任务中运行
const queue = [] // 任务队列
export function queueWatcher (watcher: Watcher) {
  const id = watcher.id
  // 重复的 Watcher 不会入列
  if (has[id] == null) {
    // 缓存 map 判断 Watcher 是否已经在队列中
    has[id] = true
    if (!flushing) {
      // 当前没有处于刷新队列状态, watcher直接进入队列
      queue.push(wathcer)
    } else {
    /**
     * 处于刷新队列状态的watcher根据id排序
     * 用户自定义的wathcer后触发
     * 保证父组件的watcher比子组件的先触发(父组件的wathcer的id会先于子组件的创建)
    */
    let i = queque.length - 1
    // id 从小到大 父组件的 watcher 优先触发
    while (i > index && queue[i].id > watcher.id) {
      i--
    }
    // id 放到比他当前 watcher 小的 后面
    queue.splice(i + 1, 0, watcher)
  }
  if (!watting) {
      waiting = true
      if (process.env.NODE_ENV !== 'production' && !config.async) {
        // 如果是同步的则直接调用刷新队列
        flushSchedulerQueue();
        return
      }
      nextTick(flushSchedulerQueue)
    }
  }
}

# nextTick

  • 每次被调用都会判断当前pending的状态,如果pending为false 则调用timerFunc在下一个任务队列执行callbacks[]
const callbacks = []
let pending = false

/**
 * 1. 用户传入的 cb 使用 try catch 包装
 * 2. flishSchedulerQueue 函数,将其放入 callbacks 数组
 * 3. pending 保证同一时刻 只会有一个 fulshCallBacks 函数
*/
export function nextTick (cb?: Function, ctx?: Object) {
  let _resolve
  callbacks.push(() => {
    if (cb) {
      try {
        cb.call(ctx)
      } catch (e) {
        // handleError
      }
    } else {
      _resolve(ctx)
    }
  })
  if (!pending) {
    pending = true
    // 执行 timeFunc
    timerFunc()
  }
  // 如果不传函数 返回的是一个 promise 返回的是第二个上下文参数
  if (!cb && typeof Promise !== 'undefined') {
    return new Promise(resolve => {
      _resolve = resolve
    })
  }
}

# timerFunc

  • 将任务放入异步任务队列中, 优先Promise微任务
let timerFunc
if (typeof Promise !== 'undefined' && idNative(Promise)) {
  const p = Promise.resolve()
  timerFunc = () => {
    p.then(fulshCallbacks)
    // ios 特殊处理
    if (isIos) setTimeout(noop)
  }
  // 使用微任务
  isUsingMicroTask = true
} else if (
  !isIE &&
  typeof MutationObserver !== 'undefined' &&
  isNative(MutationObserver) ||
  MutationObserver.toString() === '[objdect, MutationObserverConstructor]'
) {
  let counter = 1
  const observer = new MutationObserver(flushCallbacks)
  const textNode = document.createTextNode(String(counter))
  observer.observe(textNode, {
    characterData: true
  })
  timerFunc = () => {
    counter = (counter + 1) % 2
    textNode.data = String(counter)
  }
  idUsingMicroTask = true
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
  timerFunc = () => {
    setImmediate(flushCallbacks)
  }
} else {
  timerFunc = () => {
    setTimeout(flushCallbacks, 0)
  }
}

# flushCallbacks

  • pending置为 false 清空 callbacks[] 数组并执行数组中的每一个函数
function flushCallbacks () {
  pending = false
  const copies = callbacks.slice(0)
  callback.length = 0
  for (let i = 0; i < copies.length; i++) {
    copies[i]()
  }
}

# flushSchedulerQueue

  • queueWatcher(this)都会被此方法处理
function flushSchedulerQueue () {
  currentFlushTimestamp = getNow()
  // 表示正在刷新队列 queueWatcher中
  flushing = true
  let watcher, id
  /**
   * 1. 保证更新顺序由父级到子级
   * 2. 用户创建的 Wathcer 在其渲染 Wathcer 之前被执行,因为用户 Watcher 先于渲染 Watcher 创建
   * 3. 如果一个组件再其父组件的 Wathcer 执行期间被销毁, 则它的 Watcher可以被跳过
  */
  queue.sort((a, b) => a.id - b.id)
  
  for (index = 0; index < queue.length; index++) {
    wathcer = queue[index]
    // 执行 before 钩子,在使用 watch 可通过配置项 before 传递
    if (wathcer.before) {
      watcher.before()
    }
    // 清除缓存的 Watcher
    id = watcher.id
    has[id] = null
    watcher.run()
  }
  
  const activateQueue = activatedChildren.slice()
  const updatedQueue = queue.slice()
  
  // 重置has缓存对象
  // waiting = flushing = false 表示队列结束
  resetSchedulerState()
  
  callActivatedHooks(activatedQueue)
  callUpdatedHooks(updatedQueue)
}

function resetSchedulerState () {
  index = queue.length = activatedChildren.length = 0
  has = {}
  waiting = flushing = false
}