nectTick管理callbacks队列,把执行callbacks队列的函数放在异步任务中。
const callbacks = []
let pending = false
function flushCallbacks () {
pending = false
const copies = callbacks.slice(0)
callbacks.length = 0
for (let i = 0; i < copies.length; i++) {
copies[i]()
}
}
function getTimerFunc() {
let timerFunc
if (typeof Promise !== 'undefined' && isNative(Promise)) {
const p = Promise.resolve()
timerFunc = () => {
p.then(flushCallbacks)
}
} else {
// Fallback to setTimeout.
timerFunc = () => {
setTimeout(flushCallbacks, 0)
}
}
return timerFunc
}
function nextTick (cb?: Function) {
let timerFunc
callbacks.push(() => {
if (cb) {
cb.call(ctx)
}
})
if (!pending) {
pending = true
timerFunc = getTimerFunc()
timerFunc()
}
}
执行watcher队列函数作为nextTick callbacks中的一个callback。
let flushing = false
let waiting = false
function queueWatcher (watcher: Watcher) {
const id = watcher.id
if (has[id] == null) {
has[id] = true
if (!flushing) {
queue.push(watcher)
} else {
// if already flushing, splice the watcher based on its id
// if already past its id, it will be run next immediately.
let i = queue.length - 1
while (i > index && queue[i].id > watcher.id) {
i--
}
queue.splice(i + 1, 0, watcher)
}
// queue the flush
if (!waiting) {
waiting = true
nextTick(flushSchedulerQueue)
}
}
}
class Watcher {
/**
* Subscriber interface.
* Will be called when a dependency changes.
*/
update () {
queueWatcher(this)
}
}
function flushSchedulerQueue () {
flushing = true
let watcher, id
// Sort queue before flush.
// This ensures that:
// 1. Components are updated from parent to child. (because parent is always
// created before the child)
// 2. A component's user watchers are run before its render watcher (because
// user watchers are created before the render watcher)
// 3. If a component is destroyed during a parent component's watcher run,
// its watchers can be skipped.
queue.sort((a, b) => a.id - b.id)
for (index = 0; index < queue.length; index++) {
watcher = queue[index]
if (watcher.before) {
watcher.before()
}
id = watcher.id
has[id] = null
watcher.run()
}
}
通过nextTick对外提供的接口,向callbacks队列中添加callback。
Vue.nextTick(function(){
console.log(vm.$el)
})
nextTick方法之所以能够获取异步更新DOM后的DOM元素,在data的值改变后更新watcher队列的函数flushSchedulerQueue先放到nextTick的callbacks队列,nextTick对外的api再向callbacks队列添加cb,[flushSchedulerQueue, cb, cb, ....]。