vue nextTick源码解析

源码:

export const nextTick = (function () {
  const callbacks = []
  let pending = false
  let timerFunc

  function nextTickHandler () {
    pending = false
    const copies = callbacks.slice(0)
    callbacks.length = 0
    for (let i = 0; i < copies.length; i++) {
      copies[i]()
    }
  }

  if (typeof Promise !== 'undefined' && isNative(Promise)) {
    var p = Promise.resolve()
    var logError = err => { console.error(err) }
    timerFunc = () => {
      p.then(nextTickHandler).catch(logError)

      if (isIOS) setTimeout(noop)
    }
  } else if (!isIE && typeof MutationObserver !== 'undefined' && (
    isNative(MutationObserver) ||
  
    MutationObserver.toString() === '[object MutationObserverConstructor]'
  )) {

    var counter = 1
    var observer = new MutationObserver(nextTickHandler)
    var textNode = document.createTextNode(String(counter))
    observer.observe(textNode, {
      characterData: true
    })
    timerFunc = () => {
      counter = (counter + 1) % 2
      textNode.data = String(counter)
    }
  } else {

    timerFunc = () => {
      setTimeout(nextTickHandler, 0)
    }
  }

  return function queueNextTick (cb?: Function, ctx?: Object) {
    let _resolve
    callbacks.push(() => {
      if (cb) {
        try {
          cb.call(ctx)
        } catch (e) {
          handleError(e, ctx, 'nextTick')
        }
      } else if (_resolve) {
        _resolve(ctx)
      }
    })
    if (!pending) {
      pending = true
      timerFunc()
    }
    if (!cb && typeof Promise !== 'undefined') {
      return new Promise((resolve, reject) => {
        _resolve = resolve
      })
    }
  }
})()

nextTick用于延迟执行一段代码,它接收2个参数:回调函数和执行回调函数的上下文环境(也就是ctx,全名Execution Context),如果没有提供回调函数,那么将返回promise对象。

至于为何需要延时执行一段代码,vue官方也给过解释:
Vue 异步执行 DOM 更新。只要观察到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作上非常重要。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。

首先它定义了三个变量,
callbacks:存储需要执行的回调函数;
pending:标记是否正在执行回调函数;
timerFunc:触发执行回调函数;

下面是nextTickHandler函数,用来给timerFunc赋值 并执行callbacks中存储的所有回调函数。

接下来上了个大判断,vue会按照最优方案去触发回调:
1,是否支持promise,如果是,则使用promise来执行回调函数;
2,是否支持MutationObserver,如果是,则使用MutationObserver来执行回调函数,这是H5新增的一个API,用来监视DOM变动;
3,如果前两者都不支持,那就用最后的老伙计,setTimeout来执行,并设置延时为0。

最后返回一个queueNextTick函数 ,这里接收的即是用户输入的回调函数和执行上下文,并且将回调函数存入callbacks中。(queue是队列的意思)

所以其实整个nextTick函数先执行的是queueNextTick,然后用timerFunc进行延时,最后用nextTickHandler执行函数。

你可能感兴趣的:(vue)