目录
一,前言
这一篇介绍有关异步更新队列的知识,通过异步更新队列的学习和研究能够更好的理解Vue的更新机制
二,什么是异步更新队列
先看一个例子:
<div id="app">
<div id="div" v-if="show">测试文本(默认隐藏)</div>
<Button @click="toggle">显示Div</Button>
</div>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
// 控制div是否渲染,默认隐藏
show: false
},
methods:{
toggle: function () {
this.show = true;
var content = document.getElementById('div').innerHTML;
alert("content = " + content)
}
}
})
</script>
一个很简单的例子,由v-if控制div是否被渲染,默认不渲染,点击按钮对div显示/隐藏做更改
按照以往的认识:
当点击按钮切换div显隐时,由于控制显隐的变量show被置为true,div会被渲染
document.getElementById('div').innerHTML能够获取到内部html
实际执行结果
当点击按钮时,控制显隐的变量show被置为true
随后document.getElementById('div').innerHTML时会报错
错误原因:获取不到div元素
当再次点击按钮时,弹出alert:
这里就涉及到了Vue异步更新队列的概念了:
Vue在观察到数据发生变化时,并不是直接去更新DOM,
而是会开启一个队列,并缓冲在同一事件循环中发生的所有数据变化
在缓冲时,会去除重复的数据,避免多余的计算和DOM操作,
在下一个事件循环tick中,刷新队列并执行已去重的工作
报错原因:
所以,在执行this.show=true时,div还未被创建出来,
直到下一个Vue事件循环时才开始创建
这种查重机制使降低了Vue的开销:
for循环动态改变数据100次,查重后,只会执行最后一次改变,
如果没有查重机制,页面将重绘100此,而前99此是无用的,会加大开销
异步更新队列实现的选择:
由于浏览器的差异,Vue会根据当前浏览器环境选择原生Promise.then和MutationObserver
如果两者都不支持,会采用SetTimeout进行替代
三,使用异步更新队列
了解了Vue异步更新DOM的原理之后,使用Vue提供的异步队列对上边的例子进行修改
刚刚分析了报错的原因:在show=ture是div未被创建,在下一个事件循环中才开始创建
Vue提供了$nextTick告知DOM何时更新完成,我们可以在$nextTick中进行div获取
<div id="app">
<div id="div" v-if="show">测试文本(默认隐藏)</div>
<Button @click="toggle">显示Div</Button>
</div>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
// 控制div是否渲染,默认隐藏
show: false
},
methods:{
toggle: function () {
this.show = true;
// $nextTick:通知DOM更新完成
this.$nextTick(function () {
var content = document.getElementById('div').innerHTML;
alert("content = " + content)
})
}
}
})
</script>
通过简单的修改后,首次点击获取内容不再报错
四,结尾
通过对异步更新队列的介绍,加深了对子组件渲染的了解
异步更新队列是一个非常有用的东西,在使用第三方库时,很多并不是数据驱动DOM的
这时就要使用JS原声库中创建,更新,销毁的生命周期,通过$nextTick与Vue配合使用
本面试题为前端常考面试题,后续有机会继续完善。我是歌谣,一个沉迷于故事的讲述者。
欢迎一起私信交流。