Vue组件生命周期执行顺序

108 阅读2分钟

同步情况下

有如下结构代码:一个 form 父组件,两个 form-item 并列子组件,form-item 中各有一个 input 子组件。在每个组件的 beforeCreate、created、beforeMount 生命周期钩子中打印当前组件名称和钩子函数名称。结果如下:

<i-form :model="formValidate" :rules="ruleValidate">
  <i-form-item label="用户名" prop="name">
    <i-input v-model="formValidate.name"></i-input>
  </i-form-item>
  <i-form-item label="邮箱" prop="mail">
    <i-input v-model="formValidate.mail"></i-input>
  </i-form-item>
</i-form>

过程如下:在 mount 之前,是从外到内,依次执行 beforeCreate、created、beforeMount 方法,并列的两个子组件每个都先执行这三个方法。然后从内到外执行 mounted。Vue.js 的组件渲染顺序是由内而外的。

form beforeCreate
form created
form beforeMount

  form-item beforeCreate
  form-item created
  form-item beforeMount

    input beforeCreate
    input created
    input beforeMount

  form-item beforeCreate
  form-item created
  form-item beforeMount

    input beforeCreate
    input created
    input beforeMount

    input mounted

  form-item mounted

    input mounted

  form-item mounted

form mounted

结合源码看下规律

资料:《Vue 源码分析-组件化》

beforeCreate 和 created 是在_init方法中调用,这个方法是先父后子调用。

beforeMount 是在调用 mountComponent 函数中,在执行 updateComponent 函数之前调用,也是先父后子。

mounted 方法是在组件的 insert 这个钩子函数上调用,是先子后父。

beforeUpdate 是先父后子,updated 是先子后父。

组件的销毁过程最终会调用 $destroy 方法,beforeDestory 在$destroy最开始执行,所以顺序是先父后子。

执行到vm.__patch__(vm._vnode, null)时触发子组件的的销毁钩子函数,递归调用,然后才会执行 destroyd 钩子函数,所以 destroyd 执行顺序是先子后父,和 mounted 过程一样。

规律:除了 beforeCreate 和 created 这一对是两个都是先父后子。其他的三对,beforeMount 和 mounted、beforeUpdate 和 updated、beforeDestory 和 destroyd 都是 beforeXXX 先父后子,XXXed 是先子后父。

生命周期函数为异步的情况

如下代码,created 是异步函数,此时会先调用 mounted :

export default {
  methods: {
    async asyncMethod() {
      return Promise.resolve("asyncMethod");
    },
  },
  async created() {
    const data = await this.asyncMethod();
    console.log("created", data); // 2. 后打印
  },
  mounted() {
    console.log("mounted"); // 1. 先打印
  },
};