本文基于2.6,不叙述依赖收集的过程,也不介绍diff-patch阶段更新DOM的过程。仅讲解修改依赖 -> 视图更新,之间发生的重复修改去重、多次修改归并执行。
1、修改数据后会发生什么?
watcher.js 其中中有个 update 函数, 会在数据被修改后调用。它还会调用一个scheduler.js 中的queueWatcher函数。这个函数负责把响应式数据对应的watcher收集到数组queue中,除此,还做了两件很重要的事:
1、去重,修改某个响应式数据 1000次,对dom的更新只有1次。详见代码注释①。watcher会被收集到数组queue中。只收集一次,多次修改数据是没用的,执行到这里就停止了,不会重复收集。
2、归并,修改若干个响应式数据,这些修改也会被合拢到一次执行,详见代码注释②。在dom更新前,nextTick(flushSchedulerQueue)只会被执行一次,所有修改响应式数据后触发的请求,都被保存在数组数组queue中,等待flushSchedulerQueue的处理-----下面我们就介绍flushSchedulerQueue做了什么。
export 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
if (process.env.NODE_ENV !== 'production' && !config.async) {
flushSchedulerQueue()
return
}
nextTick(flushSchedulerQueue)
}
}
}
2、flushSchedulerQueue做了什么
这个函数的源码在这里:github.com/vuejs/vue/b…
前面讲到,有个数组queue,里面收集了响应式数据对应的watcher。
flushSchedulerQueue会把watcher从queue中依次取出,并执行watcher.run()。
这会触发响应式数据收集到的依赖------有可能是virtualDOM的render函数,有可能是computed计算属性,也有可能是watch侦听属性。