Vue2 nextTick

发布于:2025-04-17 ⋅ 阅读:(23) ⋅ 点赞:(0)

核心源码位置

Vue 2 的 nextTick 实现主要在 src/core/util/next-tick.js 文件中。

完整源码结构

import { noop } from 'shared/util'
import { handleError } from './error'
import { isIE, isIOS, isNative } from './env'

export let isUsingMicroTask = false

const callbacks = []
let pending = false

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

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) ||
  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)
  }
}

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()
  }
  if (!cb && typeof Promise !== 'undefined') {
    return new Promise(resolve => {
      _resolve = resolve
    })
  }
}

关键点解析

1. 回调队列管理

  • callbacks: 存储所有待执行的回调函数

  • pending: 标记是否已经有回调队列正在等待执行

  • flushCallbacks: 执行所有回调并清空队列

2. 异步执行策略 (timerFunc)

Vue 2 采用了降级策略来选择最佳的异步执行方式,优先级如下:

(1) 首选 Promise (微任务)
(2) 次选 MutationObserver (微任务)
(3) 再次选 setImmediate (宏任务)
(4) 最后选择 setTimeout (宏任务)

 

3. nextTick 函数实现

  • 支持两种调用方式:

    • 回调函数形式:nextTick(callback)

    • Promise 形式:nextTick().then(...)

  • 错误处理:捕获回调执行中的错误并通过 Vue 的错误处理系统处理

与 Vue 3 的主要区别

  1. 兼容性处理:Vue 2 有复杂的降级策略,Vue 3 只使用 Promise

  2. 微任务控制:Vue 2 明确标记 isUsingMicroTask 来跟踪是否使用微任务

  3. 实现复杂度:Vue 2 需要处理更多边界情况和浏览器怪癖

  4. Promise 返回:Vue 2 需要额外处理 Promise 返回的逻辑

设计思想

  1. 批量更新:通过回调队列实现多个更新的批量处理

  2. 异步更新:确保 DOM 更新是异步执行的,提高性能

  3. 执行时机:尽可能使用微任务以更早执行回调

  4. 兼容性:在各种环境中都能正常工作

Vue 2 的 nextTick 实现展示了框架如何在不同浏览器环境中提供一致的异步行为,同时也体现了对性能的极致追求。


网站公告

今日签到

点亮在社区的每一天
去签到