Vue2笔记:初始化流程

317 阅读2分钟

先初始化全局api

  • Vue.use set delete nextTick components directive filter //src\core\global-api\index.js

new Vue 都干了些什么

  • this._init() //src\core\instance\init.js 选项合并:用户选项和默认选项合并

  • initLifecycle(vm) src\core\instance\lifecycle.js 初始化parentparent children rootroot ref mountComponent方法也在这里定义

  • initEvents(vm) 自定义事件监听在这里,子组件的emit事件通常由父组件声明传入,为子组件保存自定事件,将来子组件从父亲中获得回调函数

  • initRender(vm) 插槽$scope, 同理自定事件,依然是孩子关心,父亲替孩子先保存,将来交给孩子使用 生成Vdom的createElement声明在这里

    内部使用:vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)

    用户调用的h:vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)

  • callHook(vm, 'beforeCreate') beforeCreate钩子能做的事情很有限,数据还没做响应处理 接下来就是处理props methods data computed wtach啦

  • initInjections(vm) 跨层级传递一定是先收集 再向下传递

  • initState(vm) 用户配置的数据处理 优先级props > methods > data

    initData

    • observe(data) 对整个data进行递归响应式处理, 规范处理 如果已经是响应式ob不再处理
    • new Observer(value) obj和array需要不同处理, 但是都需要new Dep,这是因为defineProperty只能对已有属性做getter/setter处理,访问不到新增/删除的属性, 每个对象都需要自己的dep,将来在set/delete属性时通知watcher更新

    obj处理: 遍历obj.eys => defineReactive(obj, key)

    defineReactive(): 创建dep与key一一对应

    Object.defineProperty get:dep与watcher相互建立依赖关系,如果obj[key]是个对象,还要与对象的dep建立依赖关系

    Object.defineProperty set: dep.notify()通知Watcher更新,当然Wather不会立即更新,这涉及到Vue的批量异步更新策略,如果任意属性变化都直接更新显然性能是极差的

    然后是computed watch

  • initProvide(vm)

  • callHook(vm, 'created') 响应式处理好可以在created钩子里使用数据了,当然DOM还不能访问,接下来就是挂载阶段

  • vm.mount(vm.mount(vm.options.el) //$mount分运行时版本和编译器版本,分别在src\platforms\web\runtime\index.js和src\platforms\web\entry-runtime-with-compiler.js 开发用的是运行时版本,调用mountComponent,这个fn声明 在initLifecycle中

真正的挂载开始了:

let updateComponent = () => vm._update(vm._render(), hydrating) + new Watcher(vm, updateComponent)

一个组件一个Watcher,将组件更新函数updateComponent 交给Wathcer,Wathcer会在初始化和后续更新时调用传入的updateComponent

updateComponent方法先调用render函数获得Vdom,再将Vdom传入_update()

render长这个样子↓

image.png 组件和原生tag在render内 并无区别,都使用_c来处理,后续function会区分组件和tag _v为创建文本节点

_update也声明在initLifecycle中

    const restoreActiveInstance = setActiveInstance(vm)
    vm._vnode = vnode
    // 初始化时没有prevVnode
    if (!prevVnode) {
      vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */)
    } else {
      vm.$el = vm.__patch__(prevVnode, vnode)
    }

初始化和更新都调用__patch__,初始化没有preVnode递归创建DOM树,更新阶段会根据前后Vdom进行一系列比对,对变化的部分做更新。