Vue 中 nextTick 的作用是什么?原理是什么?
作用
Vue 的 DOM 更新是异步的(批量处理),nextTick 用于在 DOM 更新完成后执行回调。
import { ref, nextTick } from 'vue'
const message = ref('')
async function updateMessage() {
message.value = 'updated'
console.log(document.getElementById('msg').textContent) // '' (DOM 还没更新)
await nextTick()
console.log(document.getElementById('msg').textContent) // 'updated' (DOM 已更新)
}为什么需要 nextTick
Vue 将数据变化后的 DOM 更新放到微任务队列中批量执行,避免频繁操作 DOM:
数据变化 → 加入更新队列 → 当前同步代码继续执行 → 微任务执行 → DOM 更新所以数据变化后立即读取 DOM 拿到的是旧值,需要 nextTick 等待 DOM 更新。
使用场景
1. 数据变化后操作 DOM
const showInput = ref(false)
async function toggleAndFocus() {
showInput.value = true
await nextTick()
// DOM 更新后才能获取到 input 元素
inputRef.value.focus()
}2. 获取更新后的元素尺寸
const items = ref([])
async function addItem() {
items.value.push(newItem)
await nextTick()
// 获取列表最新高度
const height = listEl.value.scrollHeight
listEl.value.scrollTop = height // 滚动到底部
}3. 确保子组件已更新
const data = ref([])
async function refresh() {
data.value = await fetchData()
await nextTick()
// 子组件已用新数据渲染完成
childRef.value.doSomething()
}原理
Vue 的更新机制使用微任务(Promise.then):
// 简化版
const callbacks = []
let pending = false
function flushCallbacks() {
pending = false
const copies = callbacks.slice()
callbacks.length = 0
copies.forEach(cb => cb())
}
function nextTick(cb) {
callbacks.push(cb)
if (!pending) {
pending = true
Promise.resolve().then(flushCallbacks) // 微任务
}
}
// Vue 内部数据变化时也会调用 nextTick 安排更新
function queueUpdate() {
nextTick(flushUpdateQueue)
}Vue 的异步更新策略
// 多次修改数据,只触发一次更新
state.count = 1
state.count = 2
state.count = 3
// 最终只渲染一次,count = 3Vue2 vs Vue3
- Vue2:优先
Promise.then→MutationObserver→setImmediate→setTimeout - Vue3:直接使用
Promise.resolve().then()(不再降级,需要支持 Promise)