在探究vue生命周期之前,我们先提出一个问题:
new Vue()之后,发生了什么?,当数据(data)发生变化之后又发生了什么?
生命周期流程图

由上图可知,new Vue()之后,分别经过了以上几个阶段,分别是初始化阶段,模板编译阶段,挂载阶段,更新阶段,销毁阶段,那每一个阶段都干了些什么事呢?
初始化阶段
-  首先做一些初始化操作,主要是设置一些私有属性到 vue实例中。
-  运行生命周期钩子函数 beforeCreate
-  进入注入流程,处理属性, computed,methods,data,provide,inject,最后使用代理模式将这些属性挂载到实例中。
-  运行生命周期钩子函数 created
编译阶段
- 生成render函数:如果有配置,直接使用配置的render函数,如果没有,使用运行时编译器,把模板编译成render函数。
挂载阶段
-  运行生命周期钩子函数 beforeMount
-  创建一个 Watcher,传入一个函数updeteCompontent,该函数会运行render,函数,并把render函数的返回结果vnode作为参数给_updete函数执行。// 伪代码 updateCompontent(){ _update(_render()) } new Watcher(updateCompontent)在执行 render函数的过程中会搜集所有依赖,将来依赖发生变换时会出现执行updateCompontent函数。在执行 _update的过程中,会触发patch函数,由于目前还没有就的虚拟DOM树,因此直接为当前的虚拟DOM树的每一个节点生成对应elm属性,即真实DOM。如果遇到创建一个组件实例的 vnode,则会进入组件实例化流程,该流程同vue实例流程,同上初始化阶段,编译阶段,挂载阶段。最终会把创建好的组件实例挂载到vnode的compontentInstance属性中,以便复用。
-  运行生命周期钩子函数mounted 
更新阶段
-  数据发生变化后,所有依赖该数据的 watcher都会重新运行。
-  watcher会被调度器Scheduler放到nextTick中运行,参考vue数据响应式原理,也就是微队列中,这样避免避免多个依赖的数据同时改变后被多次执行。
-  运行生命周期钩子函数beforeUpdate。 
-  updateCompontent函数重新执行:// 伪代码 updateCompontent(){ _update(_render()) } new Watcher(updateCompontent)在执行 render函数的过程中,会先去掉之前的依赖,重新收集新的依赖,将来依赖发生变化时出现运行updateCompontent函数。在执行 update函数的过程中,会触发patch函数,对比新旧两棵DOM树:当对比两棵DOM树的节点的时候,有两种情况,分别: -  普通 html节点普通 html节点的对比会导致真实节点被创建,删除,移动,更新
-  组件节点 组件节点的对比会导致组件被创建,删除,移动,更新。 a)组件节点创建的时,进入组件实例化流程,同上初始化阶段,编译阶段,挂载阶段。 b)当旧组件节点删除时,会调用旧组件的 $destroy方法删除组件,该方法会触发生命周期钩子函数beforeDestroy,然后递归调用组件的$destroy方法,然后出发生命周期钩子函数destroyedc)当组件更新时,相当于组件的 updateCompontent函数被重新触发,进入渲染流程,同更新阶段
 
-  
-  运行生命周期钩子函数updated 
销毁阶段
- 当组件销毁的时候,会调用组件的$destroy方法删除组件,该方法会调用beforeDestroy和destroyed方法
Vue.prototype.$destroy = function () {
  // 该属性标志着当前实例是否处于正在被销毁的状态
  if (vm._isBeingDestroyed) {
    return
  }
  callHook(vm, 'beforeDestroy')
  vm._isBeingDestroyed = true
  // remove self from parent
  const parent = vm.$parent
  if (parent && !parent._isBeingDestroyed && !vm.$options.abstract) {
    remove(parent.$children, vm)
  }
  // ...
  callHook(vm, 'destroyed')
  // ...
  vm.$off()
}
-  执行 beforeDestroy方法后,将当前组件实例从父组件实例的$children中删除if (parent && !parent._isBeingDestroyed && !vm.$options.abstract) { remove(parent.$children, vm) }
-  移除自身的依赖监听和事件监听,实例内响应式数据的引用 // teardown watchers if (vm._watcher) { vm._watcher.teardown() } let i = vm._watchers.length while (i--) { vm._watchers[i].teardown() } if (vm._data.__ob__) { vm._data.__ob__.vmCount-- } vm._isDestroyed = true vm.__patch__(vm._vnode, null)
-  执行 destroyed方法后,通过vm.$off()方法移除实例上的所有事件监听器,
扩展
回到开头那个问题,new Vue()之后,发生了什么?,当数据(data)发生变化之后又发生了什么?销毁呢?

// main.js
import Vue from "vue";
import App from "./App.vue";
Vue.config.productionTip = false;
new Vue({
  render: (h) => h(App),
  beforeCreate() {
    console.log("vue实例 beforeCreate");
  },
  created() {
    console.log("vue实例 created");
  },
  beforeMount() {
    console.log("vue实例 beforeMount");
  },
  mounted() {
    console.log("vue实例 mounted", this);
  },
  beforeUpdate() {
    console.log("vue实例 beforeUpdate");
  },
  updated() {
    console.log("vue实例 updated");
  },
  beforeDestroy() {
    console.log("vue实例 beforeDestroy");
  },
  destroyed() {
    console.log("vue实例 destroyed");
  },
}).$mount("#app");
// App
<template>
  <div id="app">
    <h1>App</h1>
    <A v-if="show" :count="count" />
    <button @click="count++">increase</button>
    <button @click="show = !show">toggle</button>
  </div>
</template>
<script>
import A from "./A.vue";
export default {
  components: { A },
  data() {
    return {
      show: true,
      count: 0,
    };
  },
  beforeCreate() {
    console.log("App beforeCreate");
  },
  created() {
    console.log("App created");
  },
  beforeMount() {
    console.log("App beforeMount");
  },
  mounted() {
    console.log("App mounted");
  },
  beforeUpdate() {
    console.log("App beforeUpdate");
  },
  updated() {
    console.log("App updated");
  },
  beforeDestroy() {
    console.log("App beforeDestroy");
  },
  destroyed() {
    console.log("App destroyed");
  },
};
</script>
// A
<template>
  <div>
    <h1>A compnent: {{ count }}</h1>
    <B :count="count" />
  </div>
</template>
<script>
import B from "./B.vue";
export default {
  components: { B },
  props: ["count"],
  beforeCreate() {
    console.log("A beforeCreate");
  },
  created() {
    console.log("A created");
  },
  beforeMount() {
    console.log("A beforeMount");
  },
  mounted() {
    console.log("A mounted");
  },
  beforeUpdate() {
    console.log("A beforeUpdate");
  },
  updated() {
    console.log("A updated");
  },
  beforeDestroy() {
    console.log("A beforeDestroy");
  },
  destroyed() {
    console.log("A destroyed");
  },
};
</script>
<style></style>
// B
<template>
  <div>
    <h1>B compnent: {{ count }}</h1>
  </div>
</template>
<script>
export default {
  props: ["count"],
  beforeCreate() {
    console.log("B beforeCreate");
  },
  created() {
    console.log("B created");
  },
  beforeMount() {
    console.log("B beforeMount");
  },
  mounted() {
    console.log("B mounted");
  },
  beforeUpdate() {
    console.log("B beforeUpdate");
  },
  updated() {
    console.log("B updated");
  },
  beforeDestroy() {
    console.log("B beforeDestroy");
  },
  destroyed() {
    console.log("B destroyed");
  },
};
</script>
<style></style>
当new Vue()后,会递归创建vue实例和组件实例:初始化阶段,模板编译阶段,挂载阶段。
当所有子组件实例创建完成后vue实例才创建完成
vue实例 beforeCreate
 vue实例 created
 vue实例 beforeMount
 App beforeCreate
 App created
 App beforeMount
 A beforeCreate
 A created
 A beforeMount
 B beforeCreate
 B created
 B beforeMount
 B mounted
 A mounted
 App mounted
 vue实例 mounted

当数据变化时
App beforeUpdate
 A beforeUpdate
 B beforeUpdate
 B updated
 A updated
 App updated

当组件A,B销毁时
App beforeUpdate
 A beforeDestroy
 B beforeDestroy
 B destroyed
 A destroyed
 App updated

以上仅个人理解,如有不当之处还请不吝赐教










