queueWatcher
在watcher的update方法中当没有lazy和sync配置时,watcher更新会通过queueWatcher去更新。
const queue: Array<Watcher> = []
let waiting = false
let flushing = false
function queueWatcher (watcher: Watcher) {
const id = watcher.id
if (has[id] == null) {
has[id] = true
if (!flushing) {
queue.push(watcher)
} else {
let i = queue.length - 1
while (i > index && queue[i].id > watcher.id) {
i--
}
queue.splice(i + 1, 0, watcher)
}
if (!waiting) {
waiting = true
if (process.env.NODE_ENV !== 'production' && !config.async) {
flushSchedulerQueue()
return
}
nextTick(flushSchedulerQueue)
}
}
}
queueWatcher就是将watcher加入一个队列的过程。根据watcher的id来判断是否加入过队列。
如果当前不处于刷新队列的状态,则watcher直接push入队。如果已经处在刷新队列状态,则将id从队列后往前比较,插在对应的顺序,使queue按照id从小到大排序。然后通过nextTick包裹执行flushSchedulerQueue。
flushSchedulerQueue
function flushSchedulerQueue () {
currentFlushTimestamp = getNow()
flushing = true
let watcher, id
for (index = 0; index < queue.length; index++) {
watcher = queue[index]
if (watcher.before) {
watcher.before()
}
id = watcher.id
has[id] = null
watcher.run()
}
const activatedQueue = activatedChildren.slice()
const updatedQueue = queue.slice()
resetSchedulerState()
callActivatedHooks(activatedQueue)
callUpdatedHooks(updatedQueue)
if (devtools && config.devtools) {
devtools.emit('flush')
}
}
function resetSchedulerState () {
index = queue.length = activatedChildren.length = 0
has = {}
if (process.env.NODE_ENV !== 'production') {
circular = {}
}
waiting = flushing = false
}
执行flushSchedulerQueue时表示正在刷新队列,所以flushing为true。将队列中的watcher按id从小到大排序,这么做是为了:
- 组件的更新顺序为从父级到子级,因为父组件总是在子组件之前被创建。
- 一个组件的用户 watcher 在其渲染 watcher 之前被执行,因为用户 watcher 先于 渲染 watcher 创建。
- 如果一个组件在其父组件的 watcher 执行期间被销毁,则它的 watcher 可以被跳过。
- 排序以后在刷新队列期间新进来的 watcher 也会按顺序放入队列的合适位置。
紧接着循环队列,如果watcher中有before这个配置则执行before钩子,然后执行watcher的run方法。并且将执行过的watcher的id从has这个缓存map中移除。
然后通过resetSchedulerState将has重置为{},清空队列,flushing和waiting重置为false。
waiting = flushing = false,表示刷新队列结束,表示可以像 callbacks 数组中放入新的flushSchedulerQueue 函数,并且可以向浏览器的任务队列放入下一个 flushCallbacks 函数了。
最后调用actived和update生命周期函数
补充: waiting用来判断callbacks数组中是否存放了flushSchedulerQueue函。callbacks 数组中只能存在一个 flushSchedulerQueue 函数,多了没意义。