new Vue(obj)时,底层都经历了什么

new Vue(obj)时,底层都经历了什么

new之前的准备,TARGET:web-full-dev

  1. src/core/instance/index.js

    1. 创建使用ES5语法创建Vue构造函数

    2. 接着依次执行,一下都是在Vue原型对象上的混入方法和属性,或者访问器属性等:

    initMixin(Vue) //混入_init()
    
    stateMixin(Vue) //混入$delete,$set,$watch函数,$data,$props属性,$data,$props访问器属性
    
    eventsMixin(Vue) //混入$emit,$off,$on,$once函数
    
    lifecycleMixin(Vue) //混入$forceUpdate,$destroy,_update函数
    
    renderMixin(Vue) //混入$nextTick,_render,在
    installRenderHelpers里混入一些内部函数_n,_o,_s,_l,_t,_q,_i,_m,_f,_k,_b,_v,_e,_u,_g,_d,_p
    
  2. src/core/index.js

    1. initGlobalAPI 混入一些全局API
    Object.defineProperty(Vue, 'config', configDef)
    config
    //util里的方法有风险,谨慎使用。
    Vue.util = {
        warn,
        extend,
        mergeOptions,
        defineReactive
    }
    
    Vue.set
    Vue.delete
    Vue.nextTick
    Vue.observable 
    Vue.options
    initUse(Vue) //Vue.use
    initMixin(Vue) //Vue.mixin
    initExtend(Vue) //Vue.cid, Vue.extend
    initAssetRegisters(Vue)//混入'component','directive','filter'属性
    
    1. 混入其它
        Vue.prototype.$isServer
        Vue.prototype.$ssrContext
        Vue.FunctionalRenderContext
        Vue.version
    
  3. src/platforms/web/runtime/index.js

    1. 加入属性
    Vue.config.mustUseProp
    Vue.config.isReservedTag
    Vue.config.isReservedAttr
    Vue.config.getTagNamespace
    Vue.config.isUnknownElement
    Vue.prototype.__patch__
    Vue.prototype.$mount
    
  4. src/platforms/web/entry-runtime-with-compiler.js

    1. 加入属性
    Vue.prototype.$mount //重新复制,将上一个$mount的函数缓存起来,执行完这个新函数后,执行以前的$mount
    
    Vue.compile
    
  5. 最终形成这么一个对象

Vue {
    
    
    $data: undefined,
    $isServer: false,
    $props: undefined,
    $route: '',
    $router: '',
    $ssrContext: undefined,
    __proto__: {
    
    
        $delete: ƒ del(target, key),
        $destroy: ƒ (),
        $emit: ƒ (event),
        $forceUpdate: ƒ (),
        $mount: ƒ ( el, hydrating ),
        $nextTick: ƒ (fn),
        $off: ƒ (event, fn),
        $on: ƒ (event, fn),
        $once: ƒ (event, fn),
        $set: ƒ (target, key, val),
        $watch: ƒ ( expOrFn, cb, options ),
        __patch__: ƒ patch(oldVnode, vnode, hydrating, removeOnly),
        _b: ƒ bindObjectProps( data, tag, value, asProp, isSync ),
        _d: ƒ bindDynamicKeys(baseObj, values),
        _e: ƒ (text),
        _f: ƒ resolveFilter(id),
        _g: ƒ bindObjectListeners(data, value),
        _i: ƒ looseIndexOf(arr, val),
        _init: ƒ (options),
        _k: ƒ checkKeyCodes( eventKeyCode, key, builtInKeyCode, eventKeyName, builtInKeyName ),
        _l: ƒ renderList( val, render ),
        _m: ƒ renderStatic( index, isInFor ),
        _n: ƒ toNumber(val),
        _o: ƒ markOnce( tree, index, key ),
        _p: ƒ prependModifier(value, symbol),
        _q: ƒ looseEqual(a, b),
        _render: ƒ (),
        _s: ƒ toString(val),
        _t: ƒ renderSlot( name, fallback, props, bindObject ),
        _u: ƒ resolveScopedSlots(),,
        _update: ƒ (vnode, hydrating),
        _v: ƒ createTextVNode(val),
        $data: (...),
        $isServer: (...),
        $props: (...),
        $route: (...),
        $router: (...),
        $ssrContext: (...),
        constructor: ƒ Vue(options),
        get $data: ƒ (),
        set $data: ƒ (),
        get $isServer: ƒ (),
        get $props: ƒ (),
        set $props: ƒ (),
        get $route: ƒ (),
        get $router: ƒ (),
        get $ssrContext: ƒ (),
    },
    __proto__: {
    
    
        constructor: ƒ Object(),
        hasOwnProperty: ƒ hasOwnProperty(),
        isPrototypeOf: ƒ isPrototypeOf(),
        propertyIsEnumerable: ƒ propertyIsEnumerable(),
        toLocaleString: ƒ toLocaleString(),
        toString: ƒ toString(),
        valueOf: ƒ valueOf(),
        __defineGetter__: ƒ __defineGetter__(),
        __defineSetter__: ƒ __defineSetter__(),
        __lookupGetter__: ƒ __lookupGetter__(),
        __lookupSetter__: ƒ __lookupSetter__(),
        get __proto__: ƒ __proto__(),
        set __proto__: ƒ __proto__(),
    }
}

初始化Vue完毕,等待用户new Vue

  1. 当new Vue并且传入对象时,执行_init

  2. 生成一个内部vm._uid,uid从0开始累加

    扫描二维码关注公众号,回复: 17142776 查看本文章
  3. vm._isVue为true //a flag to avoid this being observed

  4. 更新vm.$options

  5. 更新vm._renderProxy

  6. 添加一个循环引用vm._self = vm

  7. 接下来一系列函数运行

    initLifecycle(vm) 
    /* 
        该函数初始化一些实例属性
        vm.$parent
        vm.$root
        vm.$children
        vm.$refs
        vm._watcher 
        vm._inactive 
        vm._directInactive 
        vm._isMounted 
        vm._isDestroyed 
        vm._isBeingDestroyed 
     */
    initEvents(vm)
    /* 
        初始化事件
        这里的事件其实是指的是使用vm的$once, $on,$off,$emit等的事件,
        这些是用的发布订阅者模式来触发各种事件。
        这里其实就是创建了一个原型对象为null的对象而已
        vm._events = Object.create(null)
        vm._hasHookEvent = false
     */
    initRender(vm)
    /* 
        初始化属性
        vm._vnode
        vm._staticTrees
        vm.$vnode
        vm.$slots
        vm.$scopedSlots 
        vm._c和vm.$createElement
        这俩函数是对createElement的封装。
        createElement内部封装一个内部函数_createElement
        这个函数是用来创建VNode的

        劫持 vm, '$attrs'
        劫持 vm, '$listeners'
     */
    callHook(vm, 'beforeCreate')
    /* 
        这里调用生命周期钩子beforeCreate
     */
    initInjections(vm) // resolve injections before data/props
    /* 
        初始化注入,过程是将vm.$options.inject里的每个属性的from作为vm._provided的键值组成一个原型对象指向null的对象result里,并且遍历result里每个键值,执行 defineReactive(vm, key, result[key]);
        其中defineReactive函数封装的是Object.defineProperty。
     */
    initState(vm)
    /* 
        初始化对象数据
        反正在创建vue实例时,对象里的数据和方法属性都被初始化了,如下:
        初始化props,initProps
        初始化methods,initMethods
        初始化data,initData//这里很重要,这里递归对象,使用Object.defineProperty监听了对象属性
        初始化computed,initComputed
        初始化watch,initWatch
     */
    initProvide(vm) // resolve provide after data/props
    /* 
        vm.$options.provide 是否是函数,如果是就执行并把结果赋值给vm._provided,如果不是就直接返回给vm._provided
     */
    callHook(vm, 'created')
    /* 
        调用生命周期钩子created
     */
  1. 初始化vm._name

  2. vm. o p t i o n s . e l 有 值 , 就 执 行 v m . options.el有值,就执行vm. options.elvm.mount(vm.$options.el)

  3. 执行src/platforms/web/entry-runtime-with-compiler.js,判断是否有render函数,没有的话就生成一个。vm. o p t i o n s . r e n d e r , v m . options.render,vm. options.rendervm.options.staticRenderFns。
    获取template里的模板字符串,如果没有template就获取el里面的模板字符串,然后生成ast树,然后在优化ast,最终给render生成一个匿名函数,函数内部格式为with(this){return ${code}}`,这里code包含这一个createElement的封装

  4. 执行生命周期钩子beforeMount

  5. 创建watcher,把组件加入watcher里,执行updateComponent

  6. updateComponent封装了vm._render(),这函数封装了vm.$options.render最终生成VNode

  7. 执行vm.patch,进到src/core/vdom/patch.js进行diff对比进行dom的渲染

  8. 执行生命周期钩子mounted。

  9. 整体流程执行完成

猜你喜欢

转载自blog.csdn.net/sinat_25259461/article/details/105868345
new