likes
comments
collection
share

解析vue中nextTick在 Vue.js 中,nextTick 是一个非常重要的函数,它用于延迟回调函数的执行,直到

作者站长头像
站长
· 阅读数 61

在 Vue.js 中,nextTick 是一个非常重要的函数,它用于延迟回调函数的执行,直到下次 DOM 更新循环之后执行。这是因为 Vue 的数据绑定系统需要确保在数据变化后 DOM 被更新之前不执行某些依赖于 DOM 状态的操作。

实现原理

Vue 的 nextTick 主要是为了处理异步更新队列的问题。当数据发生变化时,并不是立刻更新 DOM,而是将这个更新放入一个队列中,等到当前执行栈清空时(也就是当前同步任务执行完毕),Vue 会进行一次更新,将所有需要更新的内容一次性渲染到 DOM 中,这样做是为了减少 DOM 操作次数,提高性能。

在 Vue 2 中的实现

在 Vue 2 中,nextTick 的实现在 src/core/util/next-tick.js 文件里。它利用了 setTimeout, setImmediate(如果支持的话),以及 MessageChannel 这几种不同的异步方法来实现。如果浏览器环境支持 Promise,那么它也会使用 Promise.then 来实现异步操作。

Javascript
深色版本
function nextTick (cb, ctx) {
  var _resolve
  callbacks.push(function () {
    if (cb) {
      try {
        cb.call(ctx)
      } catch (e) {
        handleError(e, 'nextTick')
      }
    } else if (_resolve) {
      _resolve(ctx)
    }
  })

  if (!pending) {
    pending = true
    if (typeof Promise !== 'undefined' && isNative(Promise)) {
      // 使用 Promise 的话,创建一个 resolve 函数,并立即调用它。
      var resolve = Promise.resolve
      // 使用 then 回调来执行
      resolve.call(Promise, function () { _resolve = $internal; })
    } else {
      // 如果没有 Promise 支持,就退而求其次使用 setImmediate 或 setTimeout
      setTimeout(_flushCallbacks, 0)
    }
  }
}

这里的关键在于 Promise.resolve() 后面跟着的 .then() 会放到 JavaScript 引擎的微任务队列中,等待当前执行栈清空后执行。这样可以确保 nextTick 的回调是在所有同步任务完成后被执行。

在 Vue 3 中的实现

Vue 3 中使用了更现代的方法来实现 nextTick,主要是基于 queueMicrotask API。这个 API 可以让回调函数在当前任务完成后的下一个微任务时机执行。如果没有 queueMicrotask 支持,则退回到 Promise.then() 方法。

Javascript
深色版本
export function nextTick(cb?: Function, delay = 0): PromiseLike<any> | void {
  if (cb) {
    // 如果提供了回调函数,则注册回调
    registerFlushSyncCallback(() => {
      queueMicrotask(() => {
        // 使用 queueMicrotask 来确保回调是在微任务时机执行
        // 这样可以保证在任何其他异步任务之前执行
        callWithAsyncErrorHandling(cb, activeInstance, SchedulerGuards.NEXT_TICK_HANDLER);
      });
    });
  } else {
    // 如果没有提供回调,则返回一个 promise
    return new Promise((res) => {
      queueMicrotask(res);
    });
  }
}

总结来说,nextTick 的主要作用是确保某些操作在 DOM 更新之后进行,从而避免了由于数据变化但 DOM 尚未更新导致的问题。通过使用异步机制(如微任务或宏任务),nextTick 能够确保在适当的时机执行回调。

转载自:https://juejin.cn/post/7426206782022074431
评论
请登录