vue源码学习总结 深入解析nextTick

本文总结了Vue的nextTick实现机制,详细阐述了其优先级:setImmediate > MessageChannel > Promise.resolve().then() > setTimeout(fn,0)。并解析了nextTick的执行过程,包括在当前tick中如何处理回调,何时执行timerFunc来处理callbacks,以及在下一tick循环中的操作。同时,文章还探讨了源码实现,重点关注了src/core/util/env.js。" 125139607,11824147,VS2022+ReSharper 自定义模板:自动添加防卫式声明与注释,"['Visual Studio', 'C++', 'ReSharper', '代码模板']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

nextTick实现机制

优先级:setImmediate() > MessageChannel > Promise.resolve().then() > setTimeout(fn,0)

执行过程

当前tick =>
当前tick第一次调用queueNextTick 的时候将回调放入callbacks中,且将timerFunc推入到宏/微任务栈中,设置pending锁=>
当前tick后续调用queueNextTick 的时候将回调放入callbacks中 =>
当前tick执行完毕后,执行timerFunc,执行所有callbacks,解除pending 锁=>
下一tick循环

源码实现

// src/core/util/env.js

/**
 * Defer a task to execute it asynchronously.
 */
export const nextTick = (function () {
  const callbacks = []
  let pending = false
  let timerFunc

  // 依次执行所有回调函数 callbacks
  function nextTickHandler () {
    pending = false
    const copies = callbacks.slice(0)
    callbacks.length = 0
    for (let i = 0; i < copies.length; i++) {
      copies[i]()
    }
  }

  // An asynchronous deferring mechanism.
  // In pre 2.4, we used to use microtasks (Promise/MutationObserver)
  // but microtasks actually has too high a priority and fires in between
  // supposedly sequential events (e.g. #4521, #6690) or even between
  // bubbling of the same event (#6566). Technically setImmediate should be
  // the ideal choice, but it's not available everywhere; and the only polyfill
  // that consistently queues the callback after all DOM events triggered in the
  // same loop is by using MessageChannel.
  /* istanbul ignore if */
  // nextTick实现机制: setImmediate() > MessageChannel > Promise.resolve().then() > setTimeout(fn,0)
  if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
    timerFunc = () => {
      setImmediate(nextTickHandler)
    }
  } else if (typeof MessageChannel !== 'undefined' && (
    isNative(MessageChannel) ||
    // PhantomJS
    MessageChannel.toString() === '[object MessageChannelConstructor]'
  )) {
    const channel = new MessageChannel()
    const port = channel.port2
    channel.port1.onmessage = nextTickHandler
    timerFunc = () => {
      port.postMessage(1)
    }
  } else
  /* istanbul ignore next */
  if (typeof Promise !== 'undefined' && isNative(Promise)) {
    // use microtask in non-DOM environments, e.g. Weex
    const p = Promise.resolve()
    timerFunc = () => {
      p.then(nextTickHandler)
    }
  } else {
    // fallback to setTimeout
    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) {
      // 第一次有回调函数进来的时候,将nextTick推入宏/微任务栈中,本次tick后续再有回调函数进来的时候,不再重复将nextTick推入宏/微任务栈中,直到nextTick被执行为止。
      pending = true
      timerFunc()
    }
    // $flow-disable-line
    if (!cb && typeof Promise !== 'undefined') {
      return new Promise((resolve, reject) => {
        _resolve = resolve
      })
    }
  }
})()

关注下再走呗 +_+

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值