zoukankan      html  css  js  c++  java
  • Vue 的 nextTick 是怎么做的

    背景

    很多人对 process.nextTick() 有个误解,认为它也是前端常用的微任务,但其实不是。

    这个方法只是在 Node 中存在,并且是个 Node 进入事件轮询的下一阶段时就会触发的一个神奇的方法。

    那么问题来了,Vue 中也实现过一个 this.$nextTick(),这是怎么做的呢?

    结论

    • 优先使用 Promise API;
    • 若不能用 Promise API,次选用 MutationObserver API,一般见于 PhantomJS IE11, iOS7, Android 4.4;
    • 若还是不能用 MutationObserver API,那就 setTimeout,见于更低版本的IE8,9,10。

    提一句在浏览器环境中 :

    常见的 micro task 有 MutationObsever 和 Promise.then

    常见的 macro task 有 setTimeout、MessageChannel、postMessage、setImmediate

    附录

    Vue 2.6.2 源码

    export const nextTick = (function () {
      // ...
      if (typeof Promise !== 'undefined' && isNative(Promise)) {
        var p = Promise.resolve()
        var logError = err => { console.error(err) }
        timerFunc = () => {
          p.then(nextTickHandler).catch(logError)
          // in problematic UIWebViews, Promise.then doesn't completely break, but
          // it can get stuck in a weird state where callbacks are pushed into the
          // microtask queue but the queue isn't being flushed, until the browser
          // needs to do some other work, e.g. handle a timer. Therefore we can
          // "force" the microtask queue to be flushed by adding an empty timer.
          if (isIOS) setTimeout(noop)
        }
      } else if (typeof MutationObserver !== 'undefined' && (
        isNative(MutationObserver) ||
        // PhantomJS and iOS 7.x
        MutationObserver.toString() === '[object MutationObserverConstructor]'
      )) {
        // use MutationObserver where native Promise is not available,
        // e.g. PhantomJS IE11, iOS7, Android 4.4
        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 {
        // fallback to setTimeout
        /* istanbul ignore next */
        /*使用setTimeout将回调推入任务队列尾部*/
        timerFunc = () => {
          setTimeout(nextTickHandler, 0)
        }
      }
    
      /*
        推送到队列中下一个tick时执行
        cb 回调函数
        ctx 上下文
      */
      return function queueNextTick (cb?: Function, ctx?: Object) {
        // ...
      }
    })()
    
  • 相关阅读:
    Leetcode Reverse Words in a String
    topcoder SRM 619 DIV2 GoodCompanyDivTwo
    topcoder SRM 618 DIV2 MovingRooksDiv2
    topcoder SRM 618 DIV2 WritingWords
    topcoder SRM 618 DIV2 LongWordsDiv2
    Zepto Code Rush 2014 A. Feed with Candy
    Zepto Code Rush 2014 B
    Codeforces Round #245 (Div. 2) B
    Codeforces Round #245 (Div. 2) A
    Codeforces Round #247 (Div. 2) B
  • 原文地址:https://www.cnblogs.com/everlose/p/12564527.html
Copyright © 2011-2022 走看看