Vue2初始化过程

92 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第29天,点击查看活动详情

想要了解new Vue(options) 发生了什么,其实就是需要从源码去理解vue的初始化过程。本文则从入口开始,一步步带你了解。

入口:vue构造函数

/src/core/instance/index.ts

image.png

这个构造函数执行了init方法,Vue.prototype._init实际上是在initMixin方法定义的。所以可以看到整个初始化过程其实就是在initMixin方法中,那我们就从这一函数中来找答案。

initMixin Vue.prototype._init

/src/core/instance/init.ts

下文对源码做了部分删减,只保留重要的部分。

  export function initMixin(Vue: typeof Component) {
  Vue.prototype._init = function (options?: Record<string, any>) {
    const vm: Component = this
   //每个 vue 实例都有一个 _uid,并且是依次递增的
    vm._uid = uid++
    ……
    
    vm._isVue = true
    //处理组件配置项
    if (options && options._isComponent) {
      //子组件:性能优化,减少原型链的动态查找,提高执行效率
      initInternalComponent(vm, options as any)
    } else {
     //根组件走这里:选项合并,将全局配置选项合并到根组件的局部配置上
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor as any),
        options || {},
        vm
      )
    }
    ……
    vm._self = vm
    //组件实例关系属性, 如 $parent、$children、$root、$refs等,这里并不是生命周期函数的初始化
    initLifecycle(vm)
    //初始化自定义事件
    initEvents(vm)
    //初始化插槽,获取this.$slots,定义this._c,即createElement方法,平时使用的h函数
    initRender(vm)
    //执行beforeCreate生命周期函数
    callHook(vm, 'beforeCreate', undefined, false /* setContext */)
    //初始化inject选项
    initInjections(vm) 
    //响应式原理的入口,处理 props、methods、data、computed、watch
    initState(vm)
    //解析组件配置项上的 provide 对象,将其挂载到 vm._provided 属性上
    initProvide(vm) 
    //执行create生命周期函数
    callHook(vm, 'created')

     ……
     //挂载
    if (vm.$options.el) {
      vm.$mount(vm.$options.el)
    }
  }
}

总结

最后根据源码总结一下Vue 的初始化过程:

  1. 处理组件配置项

  2. 初始化组件实例的关系属性,比如 $parent$children$root$refs

  3. 初始化自定义事件

  4. 调用 beforeCreate生命周期钩子函数

  5. 初始化组件的 inject 配置项

  6. 数据响应式处理,处理 props、methods、data、computed、watch 等选项

  7. 解析组件配置项上的 provide 对象

  8. 调用 created 生命周期钩子函数

  9. 如果发现配置项上有 el 选项,则自动调用 $mount 方法,也就是说有了 el 选项,就不需要再手动调用 $mount 方法,反之,没提供 el 选项则必须调用 $mount

  10. 最后进入挂载阶段