小菜鸟nextTick源码+理解

88 阅读3分钟

nextTick()

nextTick是什么?

等待下一次DOM更新刷新的工具方法;

类型: function nextTick(callback?: () => void): Promise

JS的运行机制

单线程执行机制,基于事件循环

能力检测

1.首先检测符合的执行环境
1)先检测微任务(micro task)

屏幕截图 2022-09-22 170442.png
经过以上判断微任务是否支持原生Promise,原生MutationObserver的执行环境,若都不支持,则表示当前浏览器不支持微任务;

2)再宏任务的检测(macro task)

屏幕截图 2022-09-22 171149.png
判断宏任务是否支持原生 setImmediate;

3)若以上都不支持,则使用setTimeOut

屏幕截图 2022-09-22 171511.png

执行回调队列

屏幕截图 2022-09-22 172131.png
当传入回调函数cb后,对panding进行判断,若为false,则进行timerFunc的对应方法检测,否则将回调函数推入回调队列,并进行判断。

屏幕截图 2022-09-22 172651.png
若回调函数cb未传入,则返回一个Promise.resolve()

屏幕截图 2022-09-22 182434.png

个人知识点补充

在vue2当中的应用: this.$nextTick(()=>{})

在源码中,直接调用了nextTick,未调用$nextTick:

屏幕截图 2022-09-22 150331.png 这是因为做了代理,挂载到了$上.

知识补充:代理模式 代理模式:(Proxy Pattern),是程序设计的一种设计模式。在代理模式中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。 在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。

在vue中的做代理有:Object.defineProperty()

代理模式举例: 屏幕截图 2022-09-22 152212.png

知识扩充:【1.: 在Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中

在 Vue生命周期函数中 created钩子函数中: DOM 并没有进行任何渲染, 而此时进行DOM 操作无异于是徒劳的, 所以此处一定将DOM 操作的js 代码放进Vue.nextTick 回调函数中, 与之对应的就是mounted() 钩子函数, 因为该钩子函数执行时所有的DOM 挂载和渲染都已经完成, 此时在该钩子函数中进行任何操作都不会有问题。

2.: 在数据变化后要执行某个回调函数,而这个操作需要使用随数据改变而改变的DOM结构的时候, 这个操作都应该放进Vue.nextTick () 回调函数中。

3.: Vue的官方文档中详细解释: vue 执行dom 更新是异步的, 只要是观察到数据变化, vue 将会开启一个队列, 并缓冲在同一事件循环中发生的所有数据改变。 如果同一个watcher 被多次触发,只会被推到队列中一次。 在这种缓冲时去除重复数据对于避免不必要的计算, 和DOM 操作非常重要。 然后下一个事件循环 “tick”中, vue 刷新队列执行实际(去重)工作。 在Vue 内部尝试对异步队列使用原生的promise.then 和 MessageChange, 如果执行环境不支持, 会采用setTime(()=> {} , 0)代替。】

callbacks:用来存储所有需要执行的回调函数

pending:用来标志是否正在执行回调函数

timerFunc:用来触发执行回调函数