1. 为什么Vue.js使用异步更新队列
react的setData()也是这个原理吧
Vue.js中有个队列,每当需要渲染时,会将watcher推送到这个队列中,在下一次事件循环中再让watcher触发渲染流程
如果在同一轮事件循环中有两个数据发生了变化,那么组件的watcher会收到两份通知,从而进行两次渲染。事实上,并不需要渲染两次,虚拟DOM会对整个组件进行渲染,所以只需要等所有状态修改完毕后,一次性将整个组件的DOM渲染到最新即可
要解决这个问题,收到通知watcher实例添加到队列中缓存起来,并判断队列是否已经存在相同的watcher。然后在下一次事件循环中,会让队列watcher触发渲染。这样保证了即便在同一事件循环中有两个状态发生改变,watcher最后也执行一次渲染流程
2.什么是事件循环
我们都知道JavaScript是一门单线程且非阻塞的脚本语言。
微任务:
- Promise.then
- MutationObserver
- Object.observe
- process.nextTick 宏任务
- setTimeout
- setInterval
- setImmediate
- MessageChannel
- requesAnimationFrame
- I/O
- UI 交互事件
3. 什么是执行栈
当我们执行了一个方法时,JavaScript会生成一个与这个方法对应的执行环境(context),又叫执行上下文。这个执行环境中有这个方法的私有作用域,上层作用域的指向,方法的参数,私有作用域中定义的变量以及this对象。这个执行环境会被添加到一个栈中,这个栈就是执行栈
new Vue({
methods: {
example:function(){
// 先使用nextTick 注册回调
this.$nextTick(function(){
//DOM 没有更新
})
// 然后修改数据
this.message = 'changed'
}
},
})
new Vue({
methods: {
example:function(){
// 先使用setTimeout向宏任务中注册回调
setTimeout(_ => {
// DOM 现在更新了
},0)
// 然后修改数据向微任务中注册回调 ---- watcher的更新是微任务,异步更新的
this.message = 'changed'
}
},
})
微任务优先级太高,也可能出现问题。也可强制使用宏任务的方法