vue2生命周期分析

vue官网提供的生命周期流程图 

从此图中我们可以看成4个阶段

1、初始化阶段

2、模板编译阶段

3、挂载阶段

4、销毁阶段

 初始化阶段

初始化也就是new Vue()都做了什么?我们看源码中可以得知,在new Vue的时候调用了 _init(option)一个方法

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)
}

那init做里面在哪里定义的那, 该函数定义位于源码的src/core/instance/init.js

export function initMixin (Vue) {
  Vue.prototype._init = function (options) {
    const vm = this
    // 1、合并属性
    vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
    )
    // 2 初始化
    vm._self = vm
    initLifecycle(vm) // 初始化生命周期
    initEvents(vm)     // 初始化事件
    initRender(vm)    // 初始化渲染
    callHook(vm, 'beforeCreate') // 调用生命周期钩子函数
    initInjections(vm) // 初始化 injections
    initState(vm)        // 初始化 props methods data computed watch
    initProvide(vm) // 初始化provide
    callHook(vm, 'created') // 调用生命周期钩子函数

    if (vm.$options.el) {
    //   3 进入模板编译与挂载阶段
      vm.$mount(vm.$options.el)
    }
  }
}

合并属性 

这里的合并属性是吧 vue定义的属性和 自定义的属性合并,vue定义的属性指的是 compoent、directive、filter,这也是为什么 ,<keeo-alive>  <transition>等组件不需要注册就能使用的原因。还有处理注册生命周期和 mergeOptions()等操作。

初始化initLifecycle

initLifecycle函数。该函数的逻辑非常简单,就是给实例初始化了一些属性,包括以$开头的供用户使用的外部属性($parent,$root,$children),也包括以_开头的供内部使用的内部属性。

初始化initEvents

当我们在父组件中使用子组件时可以给子组件上注册一些事件,这些事件即包括使用v-on或@注册的自定义事件,也包括注册的浏览器原生事件(需要加 .native 修饰符)。也就是说:初始化事件函数initEvents实际上初始化的是父组件在模板中使用v-on或@注册的监听子组件内触发的事件。

初始化initInjections

可能会发现,既然inject选项和provide选项都是成对出现的,那为什么在初始化的时候不一起初始化呢?为什么在init函数中调用initInjections函数和initProvide函数之间穿插一个initState函数呢?

原因是这里所说的数据就是我们通常所写data、props、watch、computed及method,所以inject选项接收到注入的值有可能被以上这些数据所使用到,所以在初始化完inject后需要先初始化这些数据,然后才能再初始化provide,所以在调用initInjections函数对inject初始化完之后需要先调用initState函数对数据进行初始化,最后再调用initProvide函数对provide进行初始化。还有把所有的写法规范成一种,集中处理。

初始化initState

初始化了5个部分,分别是 props、methods、data、computed、watch,这五个选项的顺序不是任意的,在开发中,data里可以使用props,在watch可以观察data和props

初始化computed

计算属性是有缓存的,比如某个计算属性C,它依赖data中的A,如果没有缓存的话,每次读取C时,C都回去读取A,从而触发A的get。多次触发A的get有时候是一个非常消耗性能的操作。所以Computed必须要有缓存。

computed里面控制缓存最重要的一点就是脏数据标记为dirty, dirty是watcher的一个属性。

  • 当dirty为true时,读取computed会重新计算
  • 当dirty为false时,读取computed会使用缓存

模板编译

Vue源码构建的两种版本:完整版本和只包含运行时版本。并且我们知道了模板编译阶段只存在于完整版中,在只包含运行时版本中不存在该阶段,这是因为在只包含运行时版本中,当使用vue-loadervueify时,*.vue文件内部的模板会在构建时预编译成渲染函数,所以是不需要编译的,从而不存在模板编译阶段。

然后对比了两种版本$mount方法的区别。它们的区别在于在$mount方法中是否进行了模板编译。在只包含运行时版本的$mount方法中获取到DOM元素后直接进入挂载阶段,而在完整版本的$mount方法中是先将模板进行编译,然后回过头调只包含运行时版本的$mount方法进入挂载阶段。

挂载阶段

在该阶段中所做的主要工作是创建Vue实例并用其替换el选项对应的DOM元素,同时还要开启对模板中数据(状态)的监控,当数据(状态)发生变化时通知其依赖进行视图更新。

我们将挂载阶段所做的工作分成两部分进行了分析,第一部分是将模板渲染到视图上,第二部分是开启对模板中数据(状态)的监控。两部分工作都完成以后挂载阶段才算真正的完成了。

销毁阶段

调用了实例上的vm.$destory方法后,实例就进入了销毁阶段,在该阶段所做的主要工作是将当前的Vue实例从其父级实例中删除,取消当前实例上的所有依赖追踪并且移除实例上的所有事件监听器。并且对照源码将所做的工作都进行了逐行分析。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值