运行机制全局概览
最后更新于
这有帮助吗?
最后更新于
这有帮助吗?
在new vue()之后, vue 会调用_init 函数进行初始化, 也就是 init 过程,它会初始化生命周期、事件、 props、 methods、 data、 computed 与 watch 等。 最重要的是通过object。defineProperty 设置setter 与 getter 函数。用来实现 “响应式” 以及依赖收集。
初始化之后调用 $mount 会挂载组件,如果是运行时编译,即不存在 render function 但是存在 template 的情况,需要进行「编译」步骤。
compile 编译可以分成 parse、optimize 与 generate 三个阶段,最终需要得到 render function。
parse 会用正则等方式解析 template 模版中的指令、class、style 等数据, 形成ast
optimize 标记static 静态节点, 这是vue 在编译过程中的一处优化, 当update更新界面时, 会有一个 patch 过程,diff 算法会直接跳过静态节点, 从而减少了比较的过程,优化了 patch 的性能。
generate 是将ast转化成render function 字符串的过程, 得到的结果是render的字符串以及 staticrenderfns 字符串。
在经历过 parse、optimize 与 generate 这三个阶段以后,组件中就会存在渲染 VNode 所需的 render function 了。
响应式
这里的 getter 跟 setter , 在 init 的时候通过 object.defineproperty 进行了绑定, 它使得当被设置的对象被读取的时候会执行 getter 函数,而在当被赋值的时候会执行 setter 函数
当 render function 被渲染的时候,因为会读取所需对象的值,所以会触发 getter 函数进行「依赖收集」,「依赖收集」的目的是将观察者 Watcher 对象存放到当前闭包中的订阅者 Dep 的 subs 中。形成如下所示的这样一个关系。
在修改对象的值的时候,会触发对应的 setter, setter 通知之前「依赖收集」得到的 Dep 中的每一个 Watcher,告诉它们自己的值改变了,需要重新渲染视图。这时候这些 Watcher 就会开始调用 update 来更新视图,当然这中间还有一个 patch 的过程以及使用队列来异步更新的策略,这个我们后面再讲。
render function 会被转化成 VNode 节点。Virtual DOM 其实就是一棵以 JavaScript 对象( VNode 节点)作为基础的树,用对象属性来描述节点,实际上它只是一层对真实 DOM 的抽象。 比如 isStatic (代表是否为静态节点)、 isComment (代表是否为注释节点)
更新视图
会通过 setter -> Watcher -> update 流程
当数据变化后,执行 render function 就可以得到一个新的 VNode 节点,
我们会将新的 VNode 与旧的 VNode 一起传入 patch 进行比较,经过 diff 算法得出它们的「差异」。最后我们只需要将这些「差异」的对应 DOM 进行修改即可。