深入 Vue 的 nextTick

在初学 Vue 时,我们经常会遇到这样的困惑:数据明明已经改了,可页面却没立刻变化;或者手动去获取更新后的 DOM,结果拿到的是旧值。这时候,Vue 官方会推荐我们使用 this.$nextTick()。它到底做了什么?为什么"等一下"就能解决问题?本文尝试用通俗的语言把它的作用和实现原理讲清楚。

一、nextTick 的作用

Vue 的响应式系统有一个核心设计:异步批量更新。

当你连续修改多条数据时,Vue 不会每改一次就立刻重绘页面,而是把这些变更缓存起来,等到本轮事件循环结束后再统一 patch DOM。

这样做的好处显而易见:

  • 减少不必要的重排重绘,性能更好;
  • 避免同一事件循环里多次操作 DOM 带来的闪烁或抖动。

但副作用也随之而来:

在数据改变后的同一轮同步代码里,DOM 仍然是旧的。

因此,如果你需要在视图真正更新完成后执行某些逻辑(比如获取元素新尺寸、手动聚焦、调用依赖于 DOM 的第三方库),就必须等下一轮。

nextTick它的回调会在当前批量更新结束后、浏览器重绘之前被调用。

举个最简单的例子:

js 复制代码
this.msg = 'Hello'
console.log(this.$el.textContent) // 旧值
this.$nextTick(() => {
  console.log(this.$el.textContent) // 新值
})

二、nextTick 的实现原理

浏览器事件循环里有两类异步队列:

  • 微任务(micro-task):Promise、MutationObserver;执行时机紧跟着当前栈清空后。
  • 宏任务(macro-task):setTimeout、setImmediate、MessageChannel;下一轮事件循环执行。

Vue 的源码中,nextTick 会把所有回调统一放进一个数组,然后用最快且兼容的方式调度:

  1. 如果环境支持 Promise,优先用 Promise.resolve().then() 把回调塞进微任务队列。

    这是现代浏览器最常用、延迟最低的手段。

  2. 如果 Promise 不可用,退而求其次,看是否支持 MutationObserver。

    创建一个文本节点并监听它的变动,当节点改动时触发回调,同样属于微任务。

  3. 如果上述两者都不支持,Vue 会继续降级:

    • 在 IE 里尝试 setImmediate,它介于宏任务与微任务之间,比 setTimeout 快;
    • 最后兜底 setTimeout(fn, 0),把回调放到宏任务队列末尾。

整个流程可以概括为一句话:

"能用微任务就不用宏任务,能用更快的宏任务就不用 setTimeout。"

这样既保证了回调尽早执行,又兼顾了老浏览器的兼容性。

总结

  • 作用:等本轮 DOM 批量更新完再跑回调。
  • 原理:先找微任务,再找宏任务,按优先级把回调塞进最合适的异步队列。
相关推荐
郭老二18 小时前
【前端】vue3:编译步骤
前端
不在逃避q19 小时前
Trae/Vs Code/Cursor命令行无法跑npm命令
前端·arcgis·npm
夏殇之殁19 小时前
包中创建自定义列表项。 . 使用自定义列表项进行数据绑定 . 将天气预报数据保存到本地内存表,通过LiveBindings进行显示。 ...
服务器·前端·javascript
The Chosen One98519 小时前
高进度算法模板速记(待完善)
java·前端·算法
陈随易19 小时前
MoonBit抓包模块pcap,查看电脑的每一次联网通信
前端·后端·程序员
新中地GIS开发老师20 小时前
WebGIS开发学生作品|低空航天管理与航线规划系统
前端·javascript·webgis·三维gis开发
用户0595401744620 小时前
大模型对话记忆持久化踩坑实录:用 Playwright 自动化测了 300 次,终于揪出会话丢失的真凶
前端·css
丙氨酸長鏈21 小时前
Web前端入门第 问:JavaScript 一个简单的 IndexedDB 数据库入门示例
前端·javascript·数据库
kyriewen21 小时前
面试官让我手写虚拟列表——AI生成的版本,快速滚动几下就白屏了
前端·javascript·面试
IT_陈寒1 天前
Vite热更新失效?你可能漏了这个配置
前端·人工智能·后端