1.为什么需要使用$nextTick
1.修改完数据之后需要操作dom
2.因为JS运行机制,修改dom的操作是为异步的操作 (同步代码获取不到元素)
2.先了解一下JS event Loop 机制
1.同步代码,一行一行放在Call Stack执行
2.遇到异步先记录下来,等待时机(定时,网络请求)
3.时机一到立马推入Callback Queue中
4.如Call Stack为空(即同步代码执行完毕)->执行当前的微任务(微任务会在放在一个micro task queue)-> 会尝试DOM渲染 -> 再触发Event Loop机制 (重点)
5.轮询查找Callback Quque,有则移动到Call Stack中执行
6.然后继续轮询查找
3.event Loop 区分 宏任务(MacroTask)和微任务(MicroTask)以及和DOM 渲染的关系
- 微任务:Promise、async/await
- 宏任务:setTimeout、setInterval、Ajax、DOM事件
- 微任务比宏任务执行的更早 (宏任务在DOM渲染后触发,微任务在DOM渲染前触发)
- JavaScript是单线程的,而且和DOM渲染公用一个线程,所以在JavaScript执行的时候,得留一些时机供DOM渲染
4.nextTick的源码
它在外层定义了三个变量,有一个变量看名字就很熟悉:callbacks,就是我们上面说的队列;在nextTick的外层定义变量就形成了一个闭包,所以我们每次调用$nextTick的过程其实就是在向callbacks新增回调函数的过程。
callbacks新增回调函数后又执行了timerFunc函数,pending用来标识同一个时间只能执行一次。那么这个timerFunc函数是做什么用的呢,我们继续来看代码:
isNative函数判断当前环境原生就支持,对当前环境做降级处理,尝试使用原生的Promise.then、MutationObserver和setImmediate,上述三个都不支持最后使用setTimeout;
timerFunc 最后执行flushCallbacks方法
它把callbacks数组复制一份,然后把callbacks置为空,最后把复制出来的数组中的每个函数依次执行一遍;所以它的作用仅仅是用来执行callbacks中的回调函数。
总结流程是为
- 把回调函数放入callbacks等待执行
- 将执行函数放到微任务或者宏任务中
- 事件循环到了微任务或者宏任务,执行函数依次执行callbacks中的回调