Vue中的nextTick源码分析

1)首先nextTick是可以传两个参数: 回调函数 和 环境对象

(2)nextTick做了什么:把传入的函数放入callback数组,并且执行timerFunc函数

(3)timerFunc函数: 去判断当前环境是否支持原生Promise,原生MutationObserver,试图把回调放入微任务队列去执行,如果不支持,则检查是否支持setImmediate,不支持就用setTimeout。就是对环境进行一个降级处理,去执行flushCallbacks函数

(4)flushCallbacks函数:就是for循环执行callback队列

const callbacks = []
let pending = false
let timerFunc

export function nextTick (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()
  }
  // $flow-disable-line
  if (!cb && typeof Promise !== 'undefined') {
    return new Promise(resolve => {
      _resolve = resolve
    })
  }
}


// timerFunc
export let isUsingMicroTask = false
if (typeof Promise !== 'undefined' && isNative(Promise)) {
  //判断1:是否原生支持Promise
  const p = Promise.resolve()
  timerFunc = () => {
    p.then(flushCallbacks)
    if (isIOS) setTimeout(noop)
  }
  isUsingMicroTask = true
} else if (!isIE && typeof MutationObserver !== 'undefined' && (
  isNative(MutationObserver) ||
  MutationObserver.toString() === '[object MutationObserverConstructor]'
)) {
  //判断2:是否原生支持MutationObserver
  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)) {
  //判断3:是否原生支持setImmediate
  timerFunc = () => {
    setImmediate(flushCallbacks)
  }
} else {
  //判断4:上面都不行,直接用setTimeout
  timerFunc = () => {
    setTimeout(flushCallbacks, 0)
  }
}

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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue.js的$nextTick函数是用于在DOM更新之后执行异步操作的方法。该方法的实现使用了微任务队列,即将异步操作推入到微任务队列,在DOM更新后执行异步操作。$nextTick方法是Vue.js响应式系统的重要部分,它确保了Vue.js组件的异步行为和数据响应式。 具体的实现过程如下: 1. 首先检查是否支持原生的Promise对象,如果支持,则直接返回Promise.resolve()。 2. 如果不支持原生的Promise对象,则创建一个新的Promise对象。 3. 将一个空函数推入微任务队列。 4. 在新创建的Promise对象的resolve回调,再次推入一个空函数到微任务队列。 5. 当浏览器执行到微任务队列的空函数时,DOM更新已经完成,可以执行异步操作了。 下面是$nextTick方法的源代码: ```javascript Vue.prototype.$nextTick = function(fn: Function) { return nextTick(fn, this) } ``` 其,nextTick是一个工具函数,它实现了具体的异步操作逻辑: ```javascript export function nextTick (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 if (useMacroTask) { macroTimerFunc() } else { microTimerFunc() } } // $flow-disable-line if (!cb && typeof Promise !== 'undefined') { return new Promise(resolve => { _resolve = resolve }) } } ``` 该函数定义了一个callbacks数组用于存储异步操作,当调用nextTick函数时,将回调函数push进callbacks数组,然后判断是否有待执行的异步操作,如果没有,则通过macroTimerFunc或microTimerFunc函数执行异步操作。 最后,如果调用$nextTick方法时没有传入回调函数,则会返回一个新的Promise对象,用于异步操作的等待和处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值