nextTick 是等待当前批次更新任务执行完毕的信号,由微任务队列驱动,复用 currentFlushPromise 实现精准 DOM 更新后触发,优先 Promise.then 保证在重绘前执行。

Vue 3 的 nextTick 不是简单封装 Promise,而是深度嵌入渲染调度系统的核心机制——它本质是“等待当前批次更新任务执行完毕”的信号,背后由一个精细控制的微任务队列驱动。
调度器如何与 nextTick 协同工作
Vue 3 渲染器将响应式变化(如 ref 赋值)转化为待执行的 job(例如组件 render、watcher 回调),这些 job 不会立即运行,而是统一进入一个内部队列 queue。调度器通过 queueJob 收集任务,并确保只在合适时机触发批量刷新:
- 同一 job 在一次刷新中仅执行一次(自动去重)
- job 按
id排序,保障父子组件、依赖顺序等渲染一致性 - 刷新前设置
isFlushing = true,防止递归调度或重复 flush -
currentFlushPromise是关键桥梁:它指向正在运行的flushJobs()对应的 Promise,nextTick直接复用它
nextTick 返回的 Promise 从哪来
nextTick 返回的 Promise 并非每次新建,而是动态绑定到当前调度状态:
- 若已有未完成的刷新(即
currentFlushPromise !== null),直接返回该 Promise - 否则返回一个已解析的
Promise.resolve(),相当于把回调插入本轮微任务末尾 - 无论哪种情况,回调都保证在
flushJobs()执行完、DOM 更新完成后才触发
为什么必须用微任务而非 setTimeout
微任务(Promise.then)在当前宏任务结束、渲染之前执行,这恰好卡在 Vue 更新队列清空之后、浏览器重绘之前:
使用 `@ainative/vue-sdk` 为 Vue 3 应用添加 AI 聊天功能。适用于以下场景:(1) 安装 `@ainative/vue-sdk`,(2) 在 Vue 组件中使用 `useChat` 组合式函数,(3) 提供……
立即学习“前端免费学习笔记(深入)”;
- 使用
setTimeout会落到下一个宏任务,可能错过本次 DOM 更新,导致读取旧 DOM - Vue 内部也做了优雅降级(MutationObserver → setImmediate → setTimeout),但现代环境始终优先 Promise
- 这种设计让
await nextTick()能精准捕获“视图已同步响应数据变更”的瞬间
简化版调度器可验证行为
以下逻辑可直接运行,模拟了 Vue 3 的核心流程:
(省略类型声明,保留主干逻辑)
const queue = [];<br>let isFlushing = false;<br>let currentFlushPromise = null;<br>const resolved = Promise.resolve();<br><br>function queueJob(job) {<br> if (!queue.includes(job)) queue.push(job);<br> if (!isFlushing) {<br> isFlushing = true;<br> currentFlushPromise = resolved.then(flushJobs);<br> }<br>}<br><br>function flushJobs() {<br> for (const job of queue) job();<br> queue.length = 0;<br> isFlushing = false;<br> currentFlushPromise = null;<br>}<br><br>function nextTick(fn) {<br> return fn ? currentFlushPromise.then(fn) : currentFlushPromise;<br>}

















