事件循环 + vue nextTick

34 阅读3分钟

事件循环:( 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函数使用情况,会执行一些回调函数。

  1. (nextTick)如果这两者都不被支持,就会执行setImmediate api。

  2. (nextTick)如果setImmediate 也不支持,就会回退到setTimeout (这是一个宏任务), 走到宏任务这一块是我们不希望看到的,因为如果走到了这里就会显得效率不高了。

nextTick是做什么的?

   1. 概念 : 它其实是vue中批量异步更新策略的真正执行者,它是利用了浏览器对底层的事件循环的机制,利用异步的方式往里面放回调函数。组件更新的时候不会立即去执行,而是通过nextTick去异步启动。这样组件在更新的时候可以批量的异步去更新,效率更高。基本上是用微任务的方式去执行的。那这些更新任务结束之后,一起去render,界面就会一次性去更新,用户体验会更好。

   2. 作用 :nextTick(cb) 传一个回调函数cb进去,cb就会先去队列中排队,未来再去批量更新。当数据变化,需要去访问dom最新的值的时候,就需要用到nextTick。

   3. 如何工作 : 在工作中数据发生变化,watcher 不会立马更新,会先让watch去排队,然后再去让异步去冲刷这个队列,比如说callbacks先去调用,把其它的异步函数执行完后,最后再去执行watcher.run(), 组件再真正的去调用更新函数。