Vue中如何对NextTick进行优雅降级

114 阅读1分钟

nextTick

vue为什么会有nexTick呢,现在以下代码

<div id="app">{{name}}</div>

<script>
  const vm = new Vue({
    el: '#app',
    data(){
      return {
        name: 'xujie'
      }
    },
  })
  vm.name = 'xujie--update'
  // 这里app是可以直接在window上获取到的,因为我们给id选择器
  console.log(app.innerHTML)
</script>

那么上面的输出语句输出什么呢 (^_−)☆ (^_−)☆
答案是 xujie,那么为什么是xujie呢,因为vue在做更新的时候,是做了批处理的,为了性能hhh

vm.$nextTick = () => {
  console.log(app.innerHTML)
}

改成上面的代码就是 xujie--update
原理就是用了队列加异步实现,队列用来存放任务,队列放在异步任务里面来执行,利用事件循环的机制,这样可以就到达 组件级别的更新,一个组件对应watcher。

nextTick中异步任务实现方式

一般都能想到用setTimeout来实现,但是这需要单独开一个线程,而且IE还不支持hhh。
所以Vue2中对nextTick的异步实现方式做了优雅降级
代码如下(源代码:)

export const inBrowser = typeof window !== 'undefined'
export const UA = inBrowser && window.navigator.userAgent.toLowerCase()
export const isIE = UA && /msie|trident/.test(UA)

let timerFunc
if (typeof Promise !== 'undefined' && isNative(Promise)) {
  const p = Promise.resolve()
  timerFunc = () => {
    p.then(flushCallbacks)
    if (isIOS) setTimeout(noop)
  }
  isUsingMicroTask = true
} else if (
  !isIE &&
  typeof MutationObserver !== 'undefined' &&
  (isNative(MutationObserver) ||
    // PhantomJS and iOS 7.x
    MutationObserver.toString() === '[object 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)
  }
  isUsingMicroTask = true
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
  timerFunc = () => {
    setImmediate(flushCallbacks)
  }
} else {
  timerFunc = () => {
    setTimeout(flushCallbacks, 0)
  }
}

现在还有一个 queueMicrotask Api 可以将微任务加入队列以在控制返回浏览器的事件循环之前的安全时间执行。 developer.mozilla.org/zh-CN/docs/…