You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
update(){/* istanbul ignore else */if(this.lazy){this.dirty=true}elseif(this.sync){/*同步则执行run直接渲染视图*/this.run()}else{/*异步推送到观察者队列中,下一个tick时调用。*/queueWatcher(this)}}
因为sync属性默认为false, 所以数据更新是异步的,我们继续看下queueWatcher方法
/*将一个观察者对象push进观察者队列,在队列中已经存在相同的id则该观察者对象将被跳过,除非它是在队列被刷新时推送*/exportfunctionqueueWatcher(watcher: Watcher){/*获取watcher的id*/constid=watcher.id/*检验id是否存在,已经存在则直接跳过,不存在则标记哈希表has,用于下次检验*/if(has[id]==null){has[id]=trueif(!flushing){/*如果没有flush掉,直接push到队列中即可*/queue.push(watcher)}else{
...
}// queue the flushif(!waiting){waiting=truenextTick(flushSchedulerQueue)}}}
【源码】nextTick 源码解析
前言
我们知道Vue中数据更新是异步的,如果我们在修改数据之后获取DOM中对应的数据,是无法获取到最新数据来进行相关操作,但是我们可以通过
nextTick
这个机制来实现相关需求(本文不会涉及nextTick
的基础用法)nextTick源码解析
我们先来看下
nextTick
在源码中的定义(代码有省略)我们可以发现我们使用
this.$nextTick
的时候传入的回调函数会保存在一个数组callbacks
中,然后通过pending
控制timerFunc
函数在某个时机执行那我们接下来看下
timerFunc
函数做了什么?我们可以发现代码中生成了
timerFunc
函数,然后把回调作为microTask或macroTask参与到事件循环中来, 并且依次为promise
->MutationObserver
->setImmediate
->setTimeout
这样的顺序进行降级,并且通过flushCallbacks
方法将callbacks
中的全部回调拷贝一份,然后依次执行nextTick流程梳理
虽然是读懂了
nextTick
的源码,但是我们对nextTick
如果实现对应功能,为什么可以在数据异步更新的机制下获取到最新DOM还是不了解,我们现在来梳理一下这个流程首先数据更新离不开
Watcher
, 我们看下Watcher
中的这段代码因为sync属性默认为
false
, 所以数据更新是异步的,我们继续看下queueWatcher
方法我们只需要关心最后一段代码
nextTick(flushSchedulerQueue)
就好了flushSchedulerQueue
函数的作用主要是执行视图更新的操作,它会把queue中所有的watcher取出来并执行相应的视图更新。然后通过我们对
nextTick
源码的理解,flushSchedulerQueue
方法会push到一个数组callbacks
中,如此时的数组
callbacks
中如下,flushSchedulerQueue
为第一位然后将数组
callbacks
中的回调函数按照promise
->MutationObserver
->setImmediate
->setTimeout
的顺序包装成微任务或者宏任务,最后赋值给timerFunc
,最后执行这里就涉及到了事件环相关的知识点了
同步任务执行完之后会执行异步任务,在异步任务中先执行一个宏任务,然后清空微任务队列,然后进行GUI渲染视图
也就是我们通过将
timerFunc
包装成异步任务,然后我们的nexttick
中传入的回调会在flushSchedulerQueue
执行之后执行,所以我们在回调中是可以获取到最新的DOM的,不同在于如果timerFunc
如果是微任务的话,浏览器把DOM更新的操作放在Tick执行microTask的阶段来完成,相比使用宏任务生成的一个macroTask会少一次UI的渲染。总结
nextTick源码做了什么
nextTick
函数其实做了两件事情,一是生成一个timerFunc
,把回调作为microTask或macroTask参与到事件循环中来。二是把回调函数放入一个callbacks
队列,等待适当的时机执行。(这个时机和timerFunc
不同的实现有关)为什么nextTick可以获取到最新DOM
因为在数据更新的时候会调用
nexttick
方法,将更新视图的flushSchedulerQueue
方法作为第一位放入callbacks
中,依次遍历callbacks
队列的时候flushSchedulerQueue
先执行,所以后序的回调中因为视图已经更新了,所以可以获取最新的DOM为什么说DOM更新是异步的
因为Vue源码中将视图更新的方法
flushSchedulerQueue
通过nexttick
来调用,所以最后会被包装成宏任务或者微任务,利用事件环的概念,如果宏任务的话会在下一个tick中执行,如果是微任务的话会在当前tick中执行The text was updated successfully, but these errors were encountered: