继续input的数据流向,之前讲到了input中的Dep是保存了3个Watcher对象的引用,其中会有一个Watcher是跟整个页面的渲染有关系的,这个就是用来封装vnode的处理。
当遍历Dep这个保存Watcher数组的时候,会把Watcher加入到一个异步的队列中进行处理
代码进行了简化
function queueWatcher(watcher) {
var id = watcher.id;
if (has[id] == null) {
has[id] = true;
queue.push(watcher);
nextTick(flushSchedulerQueue);
}
}
function flushSchedulerQueue() {
queue.sort(function(a, b) { return a.id - b.id; });
for (index = 0; index ) {
watcher = queue[index];
id = watcher.id;
has[id] = null;
watcher.run();
}
}
这里很关键的一个点就是针对queue进行了排序,原因就是其中有一个Wacher是保存了vnode了,因为最后一步才是vnode的对比更新。必须让前面的Watcher更新数据完毕后,最后vnode才能做真正的对比,不过computed的Wacher不会加入到这个队列中,它会再编译树中动态的执行。
当前面的Watcher执行完毕后,调到最后一个Watcher,可以看到对应的代码
vm._update(vm._render(), hydrating);
通过vm._render方法构建vnode
通过vm._update 对比vnode,并渲染到页面中
vm._render
初始化的时,会通过构建出来的JS描述树,生成初始vnode,去绘制初始页面。每次DOM变化的时候,我们还是需要重新构建这个描述树,通过这个描述树去构建新的vnode
这个描述树生成相当复杂,vue2内部专门会有一个AST是干这个事的
对应的结构是这样的,这个可以其实就是真实DOM树的一个结构映射了: