一.定义【nextTick, 事件循环】
nextTick的由来
由于vue是数据驱动视图更新,是异步的,即修改数据的当下,视图不会立刻更新,会加入任务队列中,等同一事件循环中的所有数据变化完成之后,再统一进行视图更新
nextTick的触发时机
在同一事件循环中的数据变化后,dom完成更新,立即执行nextTick内的任务队列
应用场景
需要在视图更新之后,基于新的视图(DOM)进行操作
主线程完成同步任务的执行,将异步任务加入到任务队列中,主线程完成同步任务后,从任务队列中提取队首的任务(macrotask),放入主线程执行栈中,执行完毕后,再从任务队列中提取任务(macrotask),重复该操作,该过程称为事件循环
简单总结:
同步代码执行——》查找异步队列(macrotask queue),推入执行栈,执行callback1[事件循环1]——》查找异步队列(macrotask queue),推入执行栈,执行callback2[事件循环2]...
即每一个异步callback,最终都会形成自己独立的一个事件循环
任务队列的类型
- microtask queue(微任务)promise MutationObserver nextTick
唯一,整个事件循环中,仅存在一个队列,执行为同步按队列顺序执行 - macrotask queue(宏任务)setTimeout setIntrval script
不唯一,存在一定的优化级(用户I/O部分优先级更高),异步执行
个人总结: 执行栈按顺序执行,碰到同步任务直接执行,碰到异步任务,Marco task 加入 宏任务队列, micro task 加入 微任务队列——》
执行栈同步任务按顺序执行完成后,调用微任务队列中的任务按顺序执行(先进先出)——》
以上完成一次事件循环——》
从宏任务队列中提出首个宏任务进行第二次事件循环——》
重复上面的操作
案例:
<template>
<div>
<ul>
<li v-for="item in list1">{{item}}</li>
</ul>
<ul>
<li v-for="item in list2">{{item}}</li>
</ul>
</div>
</template>
<script type="text/javascript">
export default {
data() {
return {
list1: [],
list2: [],
}
},
created() {
this.composeList12()
this.composeList34()
this.$nextTick(function() {
// DOM 更新了
console.log('finished test ' + new Date().toString())
console.log(document.querySelectorAll('li').length)
})
},
methods: {
composeList12() {
let me = this
let count = 10000
for (let i = 0; i < count; i++) {
Vue.set(me.list1, i, 'I am a 测试信息~~啦啦啦' + i)
}
console.log('finished list1 ' + new Date().toString())
for (let i = 0; i < count; i++) {
Vue.set(me.list2, i, 'I am a 测试信息~~啦啦啦' + i)
}
console.log('finished list2 ' + new Date().toString())
this.$nextTick(function() {
// DOM 更新了
console.log('finished tick1&2 ' + new Date().toString())
console.log(document.querySelectorAll('li').length)
})
},
composeList34() {
let me = this
let count = 10000
for (let i = 0; i < count; i++) {
Vue.set(me.list3, i, 'I am a 测试信息~~啦啦啦' + i)
}
console.log('finished list3 ' + new Date().toString())
this.$nextTick(function() {
// DOM 更新了
console.log('finished tick3 ' + new Date().toString())
console.log(document.querySelectorAll('li').length)
})
setTimeout(me.setTimeout1, 0)
},
setTimeout1() {
let me = this
let count = 10000
for (let i = 0; i < count; i++) {
Vue.set(me.list4, i, 'I am a 测试信息~~啦啦啦' + i)
}
console.log('finished list4 ' + new Date().toString())
me.$nextTick(function() {
// DOM 更新了
console.log('finished tick4 ' + new Date().toString())
console.log(document.querySelectorAll('li').length)
})
}
}
}
</script>
// 打印结果
> finished list1
> finished list2
> finished list3
> finished tick1&2
> 30000
> finished tick3
> 30000
> finished test
> 30000
> finished list4
> finished tick4
> 40000
文章参考:
https://www.cnblogs.com/hity-tt/p/6729118.html
http://www.cnblogs.com/hity-tt/p/6733062.html
网友评论