Vue.js 源码剖析-响应式原理、虚拟 DOM、模板编译和组件化

285 阅读2分钟

作业

1、请简述 Vue 首次渲染的过程。

  • 初始化Vue的静态成员、实例成员
  • new Vue() 实例化Vue 的构造函数
  • 在Vue 的构造函数中调用_init()
  • 调用vm.$mount()
    • 没有传入render时,对模板进行编译生成一个render函数
    • 有传入render 时,就跳过上一步的编译过程
    • 调用mountComponent方法
  • 在mountComponent 定义了updateComponent方法
    • 调用vm._render(), 实现将真实Dom 转换成虚拟Dom Vnode,并作为下一步的一个参数
    • 调用vm._update(vm._render()),将上一步的vm._render()获取到的Vnode 作为新节点 ,和老节点进行一个diff 比较,将比较结果记录到vm.$el 中
  • 创建渲染watcher ,并且把updateComponent作为参数
    • 在Watcher 的内部调用其内部的方法get时,执行updateComponent() 然后进行视图的更新
  • 首次渲染结束

2、请简述 Vue 响应式原理。

Vue 内部在初始化的时候会遍历data 中的每一个属性,使用Object.defineProperty() 对每一个属性进行getter/setter 数据劫持。在首次渲染中,$mount进行实例挂载的时候,调用render函数 ,会触发调用属性的get方法,创建Dep对象,调用depend方法,进行依赖收集,将有引用该属性的Watcher对象添加到Dep对象中的subs订阅者集合中去。当某个属性的属性值发生变化时,会触发该属性的set方法,在set内部又调用了dep 的notice 方法,对这个属性的订阅者集合进行遍历,调用每一个Watcher 进行视图的异步更新

3、请简述虚拟 DOM 中 Key 的作用和好处。 作用:对Vnode节点进行唯一性标识 好处:在数据发生变化后,视图对应的地方也要发生变化,这时候会使用diff算法来遍历比较新老Vnode的差异。不使用key 的情况下,只要满足标签相同即可对子节点进行更新,这样做增加了Dom 的操作。然而,使用key 的话,必须要满足key 和 标签都相同的情况下才进行更新子节点,能够最大限度的重用老节点的Dom结构,减少了Dom操作

4、请简述 Vue 中模板编译的过程。

前置条件:

  1. 在编译和运行时版本的vue下

  2. 实例化 Vue(options), options中没有手写render函数

编译过程:

  1. 调用baseCompile(template)
  2. 调用pasre方法,将template 转换成ast抽象语法树
  3. 调用optimize, 对ast进行优化,标志出ast中的静态子树,在重新渲染的时候,不需要重新生成节点,在patch 中直接跳过对比
  4. 调用generate,将ast 生成对应的JS 创建代码
  5. 将上一步生成的JS 代码,通过createFunction方法,生成一个匿名函数
  6. 将render、staticRenderFns对应的匿名函数,挂载到vue实例上的options对应的render和staticRenderFns属性上