# vue 运行机制

# 初始化 new vue()

new Vue() 之后。 Vue 会调用 _init 函数进行初始化,也就是这里的 init 过程,它会初始化生命周期、事件、props、 methods、 data、 computed 与 watch等。其中最重要的是通过 Object.defineProperty 设置 settergetter 函数,用来实现「响应式」以及「依赖收集」

# compile 编译

编译可分为 三个阶段

  • parse (会用正则等方式解析 template 模板中的指令、class、style等数据,形成AST)
  • optimize (的主要作用是标记 static 静态节点,这是 Vue 在编译过程中的一处优化,后面当 update 更新界面时,会有一个 patch 的过程, diff 算法会直接跳过静态节点,从而减少了比较的过程,优化了 patch 的性能)
  • generate (是将 AST 转化成 render function 字符串的过程,得到结果是 render 的字符串以及 staticRenderFns 字符串)
    在经历了三个阶段后,组件中就会存在渲染VNode所需的render function

# 响应式 数据双向绑定

在vue初始化时 数据通过了Object.defineProperty进行双向绑定,当数据被读取时会执行get方法 当数据被修改时会执行set方法从而进行数据的渲染
get 的 在渲染的时候会进行 依赖收集,的目的是将观察者 Watcher 对象存放到当前闭包中的订阅者 Depsubs 中 在set修改的时候会通知依赖收集,告诉他们被依赖的数据改变了,需要在重新更新视图,当然这中间还有一个 patch 的过程以及 使用队列来异步更新 的策略

# Virtual DOM

render function 会被转化成 VNode 节点。Virtual DOM 其实就是一棵以 JavaScript 对象( VNode 节点)作为基础的树,用对象属性来描述节点,实际上它只是一层对真实 DOM 的抽象。

# 更新视图

当数据变化后,执行render function就可以得到一个新的 VNode 节点,我们如果想要得到新的视图,最简单粗暴的方法就是直接解析这个新的 VNode 节点,然后用 innerHTML 直接全部渲染到真实 DOM 中。但是其实我们只对其中的一小块内容进行了修改,这样做似乎有些「浪费」。

那么我们为什么不能只修改那些「改变了的地方」呢?这个时候就要介绍我们的「patch」了。我们会将新的 VNode 与旧的 VNode 一起传入 patch 进行比较,经过 diff 算法得出它们的「差异」。最后我们只需要将这些「差异」的对应 DOM 进行修改即可

# 总结

vue运行机制

setter -> watcher -> updata -> render function -> VNode -> patch -> diff -> change