notify () { // 通知依赖更新
// stabilize the subscriber list first
const subs = this.subs.slice()
if (process.env.NODE_ENV !== 'production' && !config.async) {
// subs aren't sorted in scheduler if not running async
// we need to sort them now to make sure they fire in correct
// order
subs.sort((a, b) => a.id - b.id)
}
for (let i = 0, l = subs.length; i < l; i++) {
subs[i].update() // 依赖中的update方法
}
}
Jobs with duplicate IDs will be skipped unless it's
pushed when the queue is being flushed.
*/
export function queueWatcher (watcher: Watcher) {
const id = watcher.id // 过滤watcher,多个属性可能会依赖同一个watcher
if (has[id] == null) {
has[id] = true
if (!flushing) {
queue.push(watcher) // 将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
我们先来想一个问题:如果
Vue
不采用异步更新,那么每次数据更新时是不是都会对当前组件进行重写渲染呢?答案是肯定的,为了性能考虑,会在本轮数据更新后,再去异步更新视图。
通过一张图来说明
Vue
异步更新的流程:dep.notify()
通知watcher
进行更新操作。对应源码src/core/observer/dep.js
中的37行。notify
方法中,遍历subs
,执行subs[i].update()
方法,也就是依次调用watcher
的update
方法。对应源码src/core/observer/watcher.js
的164行update
函数中的queueWatcher
方法。对应源码src/core/observer/scheduler.js
的164行。/**
pushed when the queue is being flushed. */ export function queueWatcher (watcher: Watcher) { const id = watcher.id // 过滤watcher,多个属性可能会依赖同一个watcher if (has[id] == null) { has[id] = true if (!flushing) { queue.push(watcher) // 将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) // 调用nextTick方法,在下一个tick中刷新watcher队列 } } }