快捷搜索:  汽车  科技

vue可以简化哪些开发过程(源码学习:当我们new)

vue可以简化哪些开发过程(源码学习:当我们new)第二步:编译初始化之后调用 $mount 会挂载组件,如果是运行时编译,即不存在 render function但是存在template的情况,需要进行「编译」步骤。第一步:初始化及挂载在 new Vue() 之后。 Vue 会调用 _init函数进行初始化,也就是这里的 init 过程,它会初始化:生命周期、事件、 props、 methods、 data、 computed 与 watch 等。其中最重要的是通过 Object.defineProperty 设置 setter 与 getter 函数,用来实现「响应式」以及「依赖收集。

问题:Vue.js的全局运行机制

这一节的目的主要是为了让大家对整个流程有一个大概的认识,算是一个概览预备的过程。

首先我们来看一下vue的内部流程图:

vue可以简化哪些开发过程(源码学习:当我们new)(1)

流程分析:

  1. 先进行初始化挂载init以及mount
  2. 再进行模板编译:compile,编译成渲染函数render function
  3. 再进行响应式依赖收集:render function => getter、setter => Watcher 进行update => patch 的过程以及使用队列来异步更新的策略。
  4. 依赖收集的同时生产Virtual DOM:render function 被转化成 VNode 节点
  5. 通过diff算法后进行patch更新视图

第一步:初始化及挂载

vue可以简化哪些开发过程(源码学习:当我们new)(2)

在 new Vue() 之后。 Vue 会调用 _init函数进行初始化,也就是这里的 init 过程,它会初始化:生命周期、事件、 props、 methods、 data、 computed 与 watch 等。

其中最重要的是通过 Object.defineProperty 设置 setter 与 getter 函数,用来实现「响应式」以及「依赖收集。

初始化之后调用 $mount 会挂载组件,如果是运行时编译,即不存在 render function但是存在template的情况,需要进行「编译」步骤。

第二步:编译

Vue源码中虚拟DOM构建经历 template编译成AST语法树 -> 再转换为render函数 最终返回一个VNode(VNode就是Vue的虚拟DOM节点)

compile编译可以分成 parse、optimize 与 generate 三个阶段,最终需要得到 render function。

vue可以简化哪些开发过程(源码学习:当我们new)(3)

parse:会用正则等方式解析 template 模板中的指令、class、style等数据,形成AST。AST是指抽象语法树(abstract syntax tree或者缩写为AST),或者语法树(syntax tree),是源代码的抽象语法结构的树状表现形式。

optimize:主要作用是标记 static 静态节点,这是 Vue 在编译过程中的一处优化,后面当 update 更新界面时,会有一个 patch 的过程, diff算法会直接跳过静态节点,从而减少了比较的过程,优化了 patch 的性能。

generate:是将 AST转化成 render function字符串的过程,得到结果是 render的字符串以及 staticRenderFns 字符串。

在经历过 parse、optimize 与 generate 这三个阶段以后,组件中就会存在渲染 VNode 所需的 render function 了。

第三步:响应式

vue可以简化哪些开发过程(源码学习:当我们new)(4)

这里的 getter跟 setter 已经在之前介绍过了,在 init 的时候通过 Object.defineProperty 进行了绑定,它使得当被设置的对象被读取的时候会执行 getter函数,而在当被赋值的时候会执行 setter 函数。

当 render function被渲染的时候,因为会读取所需对象的值,所以会触发getter函数进行「依赖收集」,「依赖收集」的目的是将观察者 Watcher 对象存放到当前闭包中的订阅者 Dep 的 subs 中。形成如下所示的这样一个关系。

vue可以简化哪些开发过程(源码学习:当我们new)(5)

在修改对象的值的时候,会触发对应的 setter, setter 通知之前「依赖收集」得到的 Dep 中的每一个 Watcher,告诉它们自己的值改变了,需要重新渲染视图。

这时候这些 Watcher就会开始调用 update来更新视图,当然这中间还有一个 patch 的过程以及使用队列来异步更新的策略,这个我们后面再讲。

第四步:Virtual DOM

我们知道,render function 会被转化成 VNode 节点。Virtual DOM 其实就是一棵以 JavaScript 对象( VNode 节点)作为基础的树,用对象属性来描述节点,实际上它只是一层对真实 DOM 的抽象。最终可以通过一系列操作使这棵树映射到真实环境上。由于 Virtual DOM 是以 JavaScript 对象为基础而不依赖真实平台环境,所以使它具有了跨平台的能力,比如说浏览器平台、Weex、Node 等。

比如说下面这样一个例子:

{ tag: 'div' /*说明这是一个div标签*/ children: [ /*存放该标签的子节点*/ { tag: 'a' /*说明这是一个a标签*/ text: 'click me' /*标签的内容*/ } ] }

渲染后可以得到:

<div> <a>click me</a> </div>

这只是一个简单的例子,实际上的节点有更多的属性来标志节点,比如 isStatic(代表是否为静态节点)、isComment(代表是否为注释节点)等。

第五步:更新视图

vue可以简化哪些开发过程(源码学习:当我们new)(6)

前面我们说到,在修改一个对象值的时候,会通过 setter -> Watcher -> update 的流程来修改对应的视图,那么最终是如何更新视图的呢?

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

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

欢迎关注

猜您喜欢: