用vue也有一两年了,始终对vue一知半解,不怎么了解内部的执行过程,最近在看vue源码,还是不少收获的,其中不乏浏览器事件轮询机制、闭包、设计模式等,还是非常值得一读。本篇简要记录下vue的初始化过程,具体初始化过程及内容的时序如下图所示:

  

  初始化主要执行了vue-dev\src\core\index.js和vue-dev\src\core\instance\index.js两个文件,具体执行代码如下:

  vue-dev\src\core\instance\index.js

function Vue (options) {
  if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  this._init(options)
}
// 初始化vue _init方法
initMixin(Vue)
// 初始化data, prop watch等
stateMixin(Vue)
// 初始化发布-订阅事件模型
eventsMixin(Vue)
// 初始化组件生命周期钩子
lifecycleMixin(Vue)
// 初始化nextTick, render
renderMixin(Vue)

  vue-dev\src\core\index.js

initGlobalAPI(Vue)

Object.defineProperty(Vue.prototype, '$isServer', {
  get: isServerRendering
})

Object.defineProperty(Vue.prototype, '$ssrContext', {
  get () {
    /* istanbul ignore next */
    return this.$vnode && this.$vnode.ssrContext
  }
})

// expose FunctionalRenderContext for ssr runtime helper installation
Object.defineProperty(Vue, 'FunctionalRenderContext', {
  value: FunctionalRenderContext
})

Vue.version = '__VERSION__'

  在方法initGlobalAPI中,会初始化一切Vue全局的工具方法,像我们常用的全局注册组件Vue.components,全局注册指令Vue.directives,set/delete等,具体代码如下所示:

export function initGlobalAPI (Vue: GlobalAPI) {
  // config
  const configDef = {}
  configDef.get = () => config
  if (process.env.NODE_ENV !== 'production') {
    configDef.set = () => {
      warn(
        'Do not replace the Vue.config object, set individual fields instead.'
      )
    }
  }
  Object.defineProperty(Vue, 'config', configDef)

  // exposed util methods.
  // NOTE: these are not considered part of the public API - avoid relying on
  // them unless you are aware of the risk.
  Vue.util = {
    warn,
    extend,
    mergeOptions,
    defineReactive
  }

  Vue.set = set
  Vue.delete = del
  Vue.nextTick = nextTick

  // 2.6 explicit observable API
  Vue.observable = <T>(obj: T): T => {
    observe(obj)
    return obj
  }
  // 初始化Vue构造函数的options,初始属性为components,directives,filters
  Vue.options = Object.create(null)
  ASSET_TYPES.forEach(type => {
    Vue.options[type + 's'] = Object.create(null)
  })

  // this is used to identify the "base" constructor to extend all plain-object
  // components with in Weex's multi-instance scenarios.
  // _base属性
  Vue.options._base = Vue

  extend(Vue.options.components, builtInComponents)
  // 初始化vue.use api
  initUse(Vue)
  // 初始化mixins api
  initMixin(Vue)
  // 初始化extend api
  initExtend(Vue)
  // 初始化component,directive,filter
  initAssetRegisters(Vue)
}

  在首次项目初始化的过程中,会初始化几个Vue的私有方法,后面在实例化Vue的时候,会经常用到,比如Vue实例上会挂载_init方法,在我们实例化Vue的过程中,实际上调用的是this._init方法,接收的参数options就是我们初始化时的配置项。_render方法是在我们挂载DOM时会被调用,之后会调用_update方法,每次DOM的初始化、更新,都会执行_update方法。

02-11 19:55