相信很多人会好奇Vue内部的更新机制,或者平时工作中遇到的一些奇怪的问题需要使用$nextTick
来解决,今天我们就来聊一聊Vue中的异步更新机制以及$nextTick
原理
Vue的异步更新
可能你还没有注意到,Vue异步执行DOM更新。只要观察到数据变化,Vue将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个watcher被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和DOM操作上非常重要。然后,在下一个的事件循环“tick”中,Vue刷新队列并执行实际 (已去重的) 工作。
DOM更新是异步的
当我们在更新数据后立马去获取DOM中的内容是会发现获取的依然还是旧的内容。
<template>
<div class="next_tick">
<div ref="title" class="title">{
{name}}</div>
</div>
</template>
<script>
export default {
data() {
return {
name: '前端南玖'
}
},
mounted() {
this.name = 'front end'
console.log('sync',this.$refs.title.innerText)
this.$nextTick(() => {
console.log('nextTick',this.$refs.title.innerText)
})
}
}
</script>
从图中我们可以发现数据改变后同步获取dom元素中的内容是老的数据,而在nextTick里面获取的是更新后的数据,这是为什么呢?
其实这里你用微任务或宏任务去获取dom元素中的内容也是更新后的数据,我们可以来试试:
mounted() {
this.name = 'front end'
console.log('sync',this.$refs.title.innerText)
Promise.resolve().then(() => {
console.log('微任务',this.$refs.title.innerText)
})
setTimeout(() => {
console.log('宏任务',this.$refs.title.innerText)
}, 0)
this.$nextTick(() => {
console.log('nextTick',this.$refs.title.innerText)
})
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4pWb0xxq-1656422728452)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8c393ed73c68428ba42ca5212dccc86b~tplv-k3u1fbpfcp-zoom-in-crop-mark:1956:0:0:0.image?)]
是不是觉得有点不可思议,其实没什么奇怪的,在vue源码中它的实现原理就是利用的微任务与宏任务,慢慢往下看,后面会一一解释。
DOM更新还是批量的
没错,vue中的DOM更新还是批量处理的,这样做的好处无疑就是能够最大程度的优化性能。OK这里也有看点,别着急
vue同时更新了多个数据,你觉得dom是更新多次还是更新一次?我们来试试
<template>
<div class="next_tick">
<div ref="title" class="title">{
{name}}</div>
<div class="verse">{
{verse}}</div>
</div>
</template>
<script>
export default {
name: 'nextTick',
data() {
return {
name: '前端南玖'