# vue执行逻辑

  1. initGlobalAPI(Vue) 初始化全局函数

为Vue 添加 config,util,set,delete,nextTick,observable,options, use mixin extend 'component', directive filter 等属性和方法

  1. initMixin(Vue)

给Vue的原型添加 _init方法

  1. stateMixin(Vue)

给Vue的原型添加 $data,$props,$set,$delete,$watch

  1. eventsMixin(Vue)

给Vue的原型添加 $on, $emit, $off, $once 四个方法

  1. lifecycleMixin(Vue)

给 Vue的原型添加_update,$forceUpdate, $destroy

  1. renderMixin(Vue)
  // 给Vue的原型添加
  // target._o = markOnce
  // target._n = toNumber
  // target._s = toString
  // target._l = renderList
  // target._t = renderSlot
  // target._q = looseEqual
  // target._i = looseIndexOf
  // target._m = renderStatic
  // target._f = resolveFilter
  // target._k = checkKeyCodes
  // target._b = bindObjectProps
  // target._v = createTextVNode
  // target._e = createEmptyVNode
  // target._u = resolveScopedSlots
  // target._g = bindObjectListeners
  // target._d = bindDynamicKeys
  // target._p = prependModifier
  // 以及$nextTick, _render
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  1. new Vue

初始化Vue,并且执行 this._init(options), initProxy(vm);

  1. initLifecycle(vm)

为vue实例添加属性 $parent $children $root $refs

  1. initEvents(vm)

为vue的实例 添加 _events _hasHookEvent,初始化组件通过@on监听的事件

  1. initRender(vm)

为实例添加 $slots .$scopedSlots _c $createElement $attrs $listeners 将$attrs $listeners响应式处理, 不做依赖收集

  1. callHook(vm, 'beforeCreate')

执行beforeCreate钩子

  1. initInjections(vm) 处理提供的 inject ,inject不做响应式处理
  2. initState(vm)

初始化 props methods data computed watch, 并做响应式处理

  1. initProps(vm, opts.props)
    1. for (var key in propsOptions) loop( key ); ,遍历初始化传入的props
      1. var value = validateProp(key, propsOptions, propsData, vm);
        1. validateProp对props的的属性的值进行observe,比如 props: {
          fatherProp: {
            type : Object,
            default: () => ({
              testprop: '测试props'
            })
          }
        }validateProp函数会对 {testprop: '测试props'}进行observe
      2. loop函数内部调用defineReactive(props, key, value)
        1. defineReactive函数内部调用observe(val);递归观测
    2. proxy(vm, `_props`, key),将_props 的属性代理到 vm实例上
  2. initMethods(vm, opts.methods)
    1. vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm)
  3. initData(vm)
    1. observe(data, true /* asRootData */)
      1. ob = new Observer(value)
        1. this.walk(value)
          1. defineReactive(obj, keys[i])
            1. var childOb = !shallow && observe(val); 对数据进行递归处理
  4. initComputed(vm, opts.computed)
  5. initWatch(vm, opts.watch)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  1. initProvide(vm)

给 vue实例添加 _provided属性,初始化组件的provide

  1. callHook(vm, 'created')

调用 created钩子

  1. vm.$mount(vm.$options.el)

开始执行挂载

  • 调用compileToFunctions生成编译render函数
   var ref = compileToFunctions(template, {
      outputSourceRange: "development" !== 'production',
      shouldDecodeNewlines: shouldDecodeNewlines,
      shouldDecodeNewlinesForHref: shouldDecodeNewlinesForHref,
      delimiters: options.delimiters,
      comments: options.comments
    }, this);

  // src/compiler/to-function.js
  function createFunction (code, errors) {
    try {
      return new Function(code)
    } catch (err) {
      errors.push({ err, code })
      return noop
    }
  }
  export function createCompileToFunctionFn (compile) {
    return function compileToFunctions (
      template,
      options,
      vm
    ){
      // 对模板进行编译
      const compiled = compile(template, options)
      res.render = createFunction(compiled.render, fnGenErrors)
      res.staticRenderFns = compiled.staticRenderFns.map(code => {
        return createFunction(code, fnGenErrors)
      })
      return (cache[key] = res)
    }
  }
  // src/compiler/create-compiler.js
  export function createCompilerCreator (baseCompile) {
    return function createCompiler (baseOptions) {
      function compile (
        template,
        options
      ){
        const compiled = baseCompile(template.trim(), finalOptions)
        return compiled
      }
      return {
        compile,
        compileToFunctions: createCompileToFunctionFn(compile)
      }
    }
  }

  // src/compiler/index.js
  import { createCompilerCreator } from './create-compiler'
  // `createCompilerCreator` allows creating compilers that use alternative
  // parser/optimizer/codegen, e.g the SSR optimizing compiler.
  // Here we just export a default compiler using the default parts.
  export const createCompiler = createCompilerCreator(function baseCompile (
    template: string,
    options: CompilerOptions
  ) {
    const ast = parse(template.trim(), options)
    if (options.optimize !== false) {
      optimize(ast, options)
    }
    const code = generate(ast, options)
    return {
      ast,
      render: code.render,
      staticRenderFns: code.staticRenderFns
    }
  })
  // src/platforms/web/compiler/index.js

  import { createCompiler } from 'compiler/index'
  const { compile, compileToFunctions } = createCompiler(baseOptions)
  export { compile, compileToFunctions }

  // src/platforms/web/entry-runtime-with-compiler.js
  import { compileToFunctions } from './compiler/index'
  const { render, staticRenderFns } = compileToFunctions(template, {
    outputSourceRange: process.env.NODE_ENV !== 'production',
    shouldDecodeNewlines,
    shouldDecodeNewlinesForHref,
    delimiters: options.delimiters,
    comments: options.comments
  }, this)
  // ref.render 此时已经成了 new Function('with(this){}')
  var render = ref.render;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
  • 调用function compile (){}
  • 调用function baseCompile(){}
    • var ast = parse(template.trim(), options)
    • 调用generate(ast, options);
    • 调用genElement(ast, state);
      • genChildren()
        • (children.map(function (c) { return gen(c, state); })
          • gen 函数就是 genNode,递归调用genElement生成渲染函数
           function genNode (node, state) {
            if (node.type === 1) {
              return genElement(node, state)
            } else if (node.type === 3 && node.isComment) {
              return genComment(node)
            } else {
              return genText(node)
            }
          }
          
          1
          2
          3
          4
          5
          6
          7
          8
          9
    • 调用genElement返回【code = "_c('" + (el.tag) + "'" + (data ? ("," + data) : '') + (children ? ("," + children) : '') + ")";】
    • return { render: ("with(this){return " + code + "}"), staticRenderFns: state.staticRenderFns }
  1. 调用mount.call(this, el, hydrating) 实际调用Vue.prototype.$mount
  2. mountComponent(this, el, hydrating),开始挂载组件
  • callHook(vm, 'beforeMount'); 调用 beforeMount钩子
  • updateComponent = function () { vm._update(vm._render(), hydrating); }; 定义updateComponent函数,等待调用
  1. 调用new Watcher()
new Watcher(vm, updateComponent, noop, {
  before: function before () {
    if (vm._isMounted && !vm._isDestroyed) {
      callHook(vm, 'beforeUpdate');
    }
  }
}, true /* isRenderWatcher */);
1
2
3
4
5
6
7
  • this.get()
  • this.getter.call(vm, vm);
  • updateComponent()
  • vm._render()
  • render.call(vm._renderProxy, vm.$createElement);
(function anonymous() {
  with(this) {
    return _c('div', {
      attrs: {
        "id": "app"
      }
    }, [_c('h1', [_v(_s(fatherData))]), _v(" "), _c('h2', [_v(_s(fatherProp3))]), _v(" "), _c('test-test', {
      on: {
        "xxxx": xxxx
      }
    })], 1)
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
  1. render函数内部获取了props和data定义的数据,所以调用了reactiveGetter(),开始依赖收集
  • dep.depend();
Dep.prototype.depend = function depend () {
  if (Dep.target) {
    // this 是dep实例
    // Dep.target 是watcher实例
    Dep.target.addDep(this);
  }
};
1
2
3
4
5
6
7
  • Dep.target.addDep(this); this是dep实例
  Watcher.prototype.addDep = function addDep (dep) {
    var id = dep.id;
    // this 是watcher实例
    if (!this.newDepIds.has(id)) {
      this.newDepIds.add(id);
      this.newDeps.push(dep);
      if (!this.depIds.has(id)) {
        // 依赖收集
        dep.addSub(this);
      }
    }
  };
1
2
3
4
5
6
7
8
9
10
11
12
  1. 调用vm._update(vm._render(), hydrating);
// 第一次渲染没有prevVnode, 直接移除旧的
  if (!prevVnode) {
    // initial render
    vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */);
  } else {
    // updates
    vm.$el = vm.__patch__(prevVnode, vnode);
  }
1
2
3
4
5
6
7
8
  • patch (oldVnode, vnode, hydrating, removeOnly){}
  • createElm()
 createElm(
    vnode,
    insertedVnodeQueue,
    // extremely rare edge case: do not insert if old element is in a
    // leaving transition. Only happens when combining transition +
    // keep-alive + HOCs. (#4590)
    oldElm._leaveCb ? null : parentElm,
    nodeOps.nextSibling(oldElm)
  );
1
2
3
4
5
6
7
8
9
  • setScope(vnode); 为scoped Css设置data-v-5132e20a 唯一id
  • createChildren( (vnode, children, insertedVnodeQueue))
    • checkDuplicateKeys(children); 当元素设置key的时候,比如for循环
    • 遍历生成children
      for (var i = 0; i < children.length; ++i) {
        createElm(children[i], insertedVnodeQueue, vnode.elm, null, true, children, i);
      }
    
    1
    2
    3
  1. 如果发现了自定义组件则调用 createComponentInstanceForVnode()
  • 重复执行步骤16 - 21
  1. removeVnodes([oldVnode], 0, 0); 移除老的node节点

#

  1. initEvents
  2. callHook(vm, 'beforeCreate');
  3. initState
  4. callHook(vm, 'created');
  5. 生成render函数
  6. $mount =》mountComponent(this, el, hydrating)开始挂载
  7. callHook(vm, 'beforeMount');
  8. new Watcher()
  9. updateComponent()
  10. vm._update(vm._render(), hydrating)
  11. 调用render函数
  12. 依赖收集
  13. 调用 vm._update
  14. 调用 patch函数,function patch (oldVnode, vnode, hydrating, removeOnly)
  15. 更新dom
  16. callHook(vm, 'mounted');