• 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) {
        // ...
      }
    })()
    
  • 相关阅读:
    VSCode显示多个Tab窗口
    react + antd实现动态菜单
    vue 全局插件封装--提示toast
    ElementUI之el-scrollbar+el-select组合
    vue 滚动条组件对比
    【智能车】NXP_MIMXRT1064库函数
    【模电学习】二极管的特性与参数
    【模电学习】半导体——N与P(2)
    【协议】IIC通信
    【模电学习】半导体——N与P(1)
  • 原文地址:https://www.cnblogs.com/everlose/p/12564527.html
Copyright © 2020-2023  润新知