第 11 题:Vue 的 nextTick 是什么?为什么需要它?底层原理是什么?
📌 标准回答(你在面试中应该先说的)
nextTick 用于在 下次 DOM 更新循环结束之后执行回调 。
因为 Vue 的 DOM 更新是 异步批处理 的,你修改数据后,DOM 不会立刻更新,所以想获取最新 DOM 必须放到 nextTick 里。
示例:
javascript
count.value++
await nextTick()
console.log(document.querySelector('#count').innerText)
📌 为什么需要 nextTick?(核心点)
✔ Vue 会将多次数据修改合并成一次 DOM 更新(异步)
例如:
count.value++
count.value++
count.value++
Vue 不会更新三次 DOM,而是 合并 后更新一次,提高性能。
所以 ------
如果你在数据修改后立即访问 DOM,你拿到的是 旧 DOM。
因此必须:
➡ 数据改完 → 等 DOM 更新 → 再操作 DOM
📌 底层原理(很重要)
Vue 采用 异步队列 + 微任务优先策略:
触发顺序大概是:
Promise.then()MutationObserversetImmediate(Node)setTimeout
优先使用 微任务(Promise),因为它比宏任务快。
面试官喜欢听这句话:
Vue 的
nextTick本质是利用微任务(Promise)将回调延迟到 DOM 更新完成后执行。
📌 最常见使用场景(面试官一定问)
① 获取更新后的 DOM(最常用)
ini
isShow.value = true
await nextTick()
const height = divRef.value.offsetHeight
② 动态渲染后需要初始化插件
如 echarts、swiper、editor 等:
csharp
showChart.value = true
await nextTick()
chart = echarts.init(chartRef.value)
③ 强制等待下一轮渲染后再执行动画
ini
visible.value = false
await nextTick()
visible.value = true
📌 常见误区(面试官可能故意问的)
❌ "Vue 3 的 DOM 更新是同步,所以不用 nextTick 了?"
回答:绝对错。
Vue 3 仍然采用异步批处理机制,仍然需要 nextTick。
❌ "watch 回调里 DOM 已经更新了?"
错。
watch 触发在 DOM 更新前。
📌 面试官追问(附带参考答案)
追问 1:Vue 为什么不让 DOM 同步更新?
参考回答:
- 同步更新 DOM 会导致频繁重绘、回流
- 影响性能(especially 当数据更新频繁)
- 批处理模式可以把多次更新合并成一次
一句话总结:
异步批处理是为了提升性能。
追问 2:nextTick 用 Promise 还是 setTimeout?
参考回答:
- Vue 2:
Promise.then→MutationObserver→setImmediate→setTimeout - Vue 3:直接使用 微任务调度(Promise)
Vue 3 更简化、更快速。
追问 3:能否手写一个 nextTick 的简化实现?
如果你会写这个,面试官会对你另眼相看。
ini
const callbacks = []
let pending = false
function nextTick(cb) {
callbacks.push(cb)
if (!pending) {
pending = true
Promise.resolve().then(() => {
pending = false
callbacks.forEach(fn => fn())
callbacks.length = 0
})
}
}
面试官心里给你 +20 分。
追问 4:除了 nextTick,有没有办法等 DOM 更新?
✔ watchEffect + flush: 'post'
arduino
watchEffect(() => {
console.log('DOM 已更新')
}, { flush: 'post' })
这是 Vue 3 新能力。