/** * Flush both queues and run the watchers. * nextTick的回调函数,在下一个tick时flush掉两个队列同时运行watchers */ functionflushSchedulerQueue() { currentFlushTimestamp = getNow(); 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);
// do not cache length because more watchers might be pushed // as we run existing watchers /*这里不用index = queue.length;index > 0; index--的方式写是因为不要将length进行缓存, 因为在执行处理现有watcher对象期间,更多的watcher对象可能会被push进queue */ for (index = 0; index < queue.length; index++) { watcher = queue[index]; if (watcher.before) { watcher.before(); } id = watcher.id; /*将has的标记删除*/ has[id] = null; /*执行watcher*/ watcher.run(); // in dev build, check and stop circular updates. /* 在测试环境中,检测watch是否在死循环中 比如这样一种情况 watch: { test () { this.test++; } } 持续执行了一百次watch代表可能存在死循环 */ if (process.env.NODE_ENV !== "production" && has[id] != null) { circular[id] = (circular[id] || 0) + 1; if (circular[id] > MAX_UPDATE_COUNT) { warn( "You may have an infinite update loop " + (watcher.user ? `in watcher with expression "${watcher.expression}"` : `in a component render function.`), watcher.vm ); break; } } }
// keep copies of post queues before resetting state /*得到队列的拷贝*/ const activatedQueue = activatedChildren.slice(); const updatedQueue = queue.slice();
classWatcher{ ... run() { if (this.active) { const value = this.get(); if ( value !== this.value || // Deep watchers and watchers on Object/Arrays should fire even // when the value is the same, because the value may // have mutated. isObject(value) || this.deep ) { // set new value const oldValue = this.value; this.value = value; if (this.user) { try { this.cb.call(this.vm, value, oldValue); } catch (e) { handleError( e, this.vm, `callback for watcher "${this.expression}"` ); } } else { this.cb.call(this.vm, value, oldValue); } } } } ... }
run 函数逻辑也很简单,先通过 this.get() 得到它当前的值,然后做判断,如果满足新旧值不等、新值是对象类型、deep 模式任何一个条件,则执行 watcher 的回调,注意回调函数执行的时候会把第一个和第二个参数传入新值 value 和旧值 oldValue,这就是当我们添加自定义 watcher 的时候能在回调函数的参数中拿到新旧值的原因。