事件循环:( Event Loop )
浏览器为了协调事件处理、脚本执行、网络请求和渲染等任务而制定的工作机制。
宏任务 Task: 代表一个个离散的、独立的工作单元。浏览器完成一个宏任务,在下一个宏任务执行开始前,会对页面进行重新渲染。 主要包括创建文档对象、解析HTML、执行主线JS代码以及各种事件如页面加载、输入、网络事件和定时器等。(setTimeout , setInterval , xhr)
微任务:微任务是更小的任务,是在当前宏任务执行结束后立即执行的任务。 如果存在微任务,浏览器会注定微任务之后再重新渲染。 微任务的例子有Promise回调函数、DOM变化等。(Promise , mutaition observer )
Vue nextTick ( flushSchedulerQueue ) : (你对nextTick是如何理解的?)
nextTick中会传一个cb函数参数, 这个cb函数会被封装一个高阶函数,在函数里会让try … catch … 处理一些错误,但是被封装的函数并不会立即执行,会将它存入callbacks的数组之中。
然后通过以下if判断执行异步启动。
if(!pending){
pending = true
timerFunc()
}
它只在第一次进入的时候执行一次,以后就不再执行了。
1. 这个timerFunc函数会根据平台的支持情况,来决定它是一个怎样的函数,支持Promise就用Promise,不支持就用MutationObserver ,这两种方式都是微任务。
timerFunc在它内部会执行一个叫 flushCallbacks 异步函数,在这个函数内部是对刚才的callback的循环遍历
Function flushCallbacks(){
pending = false
const copies = callbacks.slice(0)
callbacks.length = 0
for(let I = 0; I< copies.length;i++){
copies[ I ]
}
}
flushCallbacks在timerFunc 中 以callbacks的形式放进去,它在这里执行的时候其实已经被变成异步任务了,可以把它看成是一个微任务了。
nextTick会去调用flushSchedulerQueue这个函数,而flushSchedulerQueue 会遍历所有watchers的队列,执行它们的run 函数。这里真正的更新函数是watcher.run() 这个方法,而不是update函数。
在run方法里,会根据用户的一些watcher函数使用情况,会执行一些回调函数。
-
(nextTick)如果这两者都不被支持,就会执行setImmediate api。
-
(nextTick)如果setImmediate 也不支持,就会回退到setTimeout (这是一个宏任务), 走到宏任务这一块是我们不希望看到的,因为如果走到了这里就会显得效率不高了。
nextTick是做什么的?
1. 概念 : 它其实是vue中批量异步更新策略的真正执行者,它是利用了浏览器对底层的事件循环的机制,利用异步的方式往里面放回调函数。组件更新的时候不会立即去执行,而是通过nextTick去异步启动。这样组件在更新的时候可以批量的异步去更新,效率更高。基本上是用微任务的方式去执行的。那这些更新任务结束之后,一起去render,界面就会一次性去更新,用户体验会更好。
2. 作用 :nextTick(cb) 传一个回调函数cb进去,cb就会先去队列中排队,未来再去批量更新。当数据变化,需要去访问dom最新的值的时候,就需要用到nextTick。
3. 如何工作 : 在工作中数据发生变化,watcher 不会立马更新,会先让watch去排队,然后再去让异步去冲刷这个队列,比如说callbacks先去调用,把其它的异步函数执行完后,最后再去执行watcher.run(), 组件再真正的去调用更新函数。