nextTick 的使用
官方链接:https://cn.vuejs.org/api/general.html#nexttick
当你在 Vue 中更改响应式状态时,最终的 DOM 更新并不是同步生效的,而是由 Vue 将它们缓存在一个队列中,直到下一个“tick”才一起执行。这样是 为了确保在一定时间内,每个组件无论发生多少状态改变,都仅执行一次更新。
nextTick()
可以在状态改变后立即使用,以等待 DOM 更新完成。你可以传递一个回调函数作为参数,或者 await 返回的 Promise。
个人注解:vue 这样实现的目的是为了性能优化,避免不必要的资源浪费,只需要确保组件可以被正确渲染,程序可以正常运行即可,在这个基础上可以进行一定程度的性能优化。
- 示例
import { ref, nextTick } from 'vue'
const count = ref(0)
async function increment() {
count.value++
// DOM 还未更新
console.log(document.getElementById('counter').textContent) // 0
// 方式1:
await nextTick()
// DOM 此时已经更新
console.log(document.getElementById('counter').textContent) // 1
// 方式2:将更新DOM后才执行的逻辑放到nextTick的参数函数中,该回调函数会在DOM更新完成后,自动执行
nextTick(() => {
// DOM 此时已经更新
console.log(document.getElementById('counter').textContent) // 1
})
}
<button id="counter" @click="increment">{{ count }}</button>
Vue3 中的 nextTick 源码
官方链接:https://cn.vuejs.org/api/general.html#nexttick
当你在 Vue 中更改响应式状态时,最终的 DOM 更新并不是同步生效的,而是由 Vue 将它们缓存在一个队列中,直到下一个“tick”才一起执行。这样是 为了确保在一定时间内,每个组件无论发生多少状态改变,都仅执行一次更新。
nextTick()
可以在状态改变后立即使用,以等待 DOM 更新完成。你可以传递一个回调函数作为参数,或者 await 返回的 Promise。
// scheduler.ts
export function nextTick<T = void>(
this: T,
fn?: (this: T) => void
): Promise<void> {
// p 可以简单理解为是执行任务队列中的更新任务的 Promise
const p = currentFlushPromise || resolvedPromise
// fn 是传入 nextTick 的回调函数
return fn ? p.then(this ? fn.bind(this) : fn) : p
}
知识补给:Promise.then 传入的回调函数是作为一个微任务去执行的,而微任务是在 DOM 结构更新之后,DOM 被渲染到页面上之前被调用的。
理解 nexTick 实现原理的核心:nextTick 就是将传入的回调函数作为 p.then 的实参,p.then 传入的实参函数是在 Promise 对象 p 执行完成(fulfilled)时,也就是在当前更新任务队列中的更新任务全部执行完成之后才被调用,被调用时, DOM 操作已经完成,DOM 结构已更新,只是 DOM 还没有被渲染到页面中,但是已经可以通过 js 获取到修改后的 DOM。
使用 nextTick
nextTick(() => {
// DOM 此时已经更新
// do someThing
// ...
})