Vue源码探究-生命周期
本篇代码位于vue/src/core/instance/lifecycle.js
初步探索完了核心类的实现之后,接下来就要开始深入到Vue实现的具体功能部分了。在所有的功能开始运行之前,要来理解一下Vue的生命周期,在初始化函数中所有功能模块绑定到Vue的核心类上之前,最先开始执行了一个初始化生命周期的函数initLifecycle(vm)
,先来看看这个函数做了些什么。
生命周期初始化属性
1 | // 导出initLifecycle函数,接受一个Component类型的vm参数 |
initLifecycle
函数非常简单明了,主要是在生命周期开始之前设置一些相关的属性的初始值。一些属性将在之后的生命周期运行期间使用到。
生命周期初始化方法
生命周期的开始除了设置了相关属性的初始值之外,还为类原型对象挂载了一些方法,包括私有的更新组件的方法和公用的生命周期相关的方法。这些方法都包含在 lifecycleMixin
函数中,还记得这也是在定义核心类之后执行的那些函数之一,也来看看它的内容。
1 | // 导出lifecycleMixin函数,接收形参Vue, |
lifecycleMixin
函数实现了三个原型继承方法:
私有方法 _update
这个函数用于更新组件,实现数据和元素节点的无刷新更新,涉及到虚拟节点相关的一些内容,具体实现留给未来研究虚拟节点和数据更新时再深入探索。
公用方法 $forceUpdate
实现组件强制刷新,这个方法是从实例上设置的watcher对象方法中引用而来,在生命周期初始化的时候为实例设置了一个私有的_watcher属性,在观察者系统的功能模块中具体实现了这一对象,也放到以后在去深入了解。这里只要知道可以调用这个共有的API实现手动更新组件。
公用方法 $destroy
实例销毁方法。在刚开始讨论生命周期的开启时,就了解到了这个销毁Vue实例组件的方法,凡事都有始有终,从这里可以明白无误的认识到,Vue实例是一个生命过程。那么在Vue的生命过程中有哪些重要的阶段,是接下来要继续探索的内容。
生命周期过程
最明白无误的生命周期过程在官方文档中有介绍,这里再贴上这张经典的图示来做个纪念。
生命周期钩子
对照生命周期图示中呈现的各种钩子函数,从源码总结了他们的调用时机,顺便又学习一遍钩子执行的线路:
callHook(vm, ‘beforeCreate’)
1
2
3
4initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate')从
new Vue()
创建实例开始 ,在执行_init()
方法时开始初始化了生命周期、事件和渲染。紧接着就调用了beforeCreate
钩子函数。此时与数据相关的属性都还没有初始化 ,所以在这个阶段想要用获取到组件的属性是无法成功的。callHook(vm, ‘created’)
1
2
3
4initInjections(vm) // resolve injections before data/props
initState(vm)
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created')在
beforeCreate
调用后,继续初始化属性注入、状态、子组件属性提供器。然后立即调用created
钩子,这个时候数据可访问了,但是还没有开始渲染页面,适合一些数据的初始化操作。另外provide和injection主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中,所以此刻我们主要注意的是观察器的初始化完成。
到这一步之后,就开始进入渲染流程。callHook(vm, ‘beforeMount’)
渲染的执行流程稍微复杂一些,实例装载方法 $mount
是根据平台的不同需求而分别定义的,在执行 $mount
方法的时候,开始装载组件,具体内容在 mountComponent
函数中,在此函数的最开始时渲染虚拟节点之前就调用了 beforeMount
钩子,然后开始执行 updateComponent
来渲染组件视图。
- callHook(vm, ‘mounted’)
紧接着上面视图的渲染完成,mounted
钩子被调用。在这个钩子中还调用了内部的插入钩子渲染引用的子组件,这之后就开始处于生命周期的正常运转期。在这个时期内观察器系统开始监控所有的数据更新,进入数据更新并重新渲染视图的循环中。
- callHook(vm, ‘beforeUpdate’)
在观察器的作用下,如果有数据的更新时就会先调用 beforeUpdate
钩子。
- callHook(vm, ‘updated’)
当数据更新并且完成视图渲染后调用 updated
钩子。这个钩子和上面的钩子会一直在生命周期运转期里不断被触发。
- callHook(vm, ‘activated’) 和 callHook(vm, ‘deactivated’)
activated
和 deactivated
这两个特殊钩子是在使用 keep-alive
组件的时候才有效。分别在组件被激活或切换到其他组件的时候被调用。 使用 keep-alive
模式在切换到不同组件视图的过程中不会进行重新加载,这就意味着其他的钩子函数都不会被调用,如果在离开页面和进入页面的时候执行某些操作,这两个钩子就非常有用。
- callHook(vm, ‘beforeDestroy’) 和 callHook(vm, ‘destroyed’)
beforeDestroy
和 destroyed
钩子与上面的两个钩子相对应,是在普通模式下会有效的钩子。实例的生命周期的最后阶段就是执行销毁,在销毁之前调用 beforeDestroy
。然后清除了所有的数据引用、观察器和事件监听器。最后调用 destroyed
宣告生命周期的完全终止。
之前看过很多次Vue的生命周期图,但在学习源码之前并没有特别深的感触,现在随着探索源码的深入,终于感觉到在慢慢了解这个过程的意义。整个生命周期的构建过程并不是最难的实现部分,但它是整个架构的背后支撑力量,有了生命周期的正常运转,才能一步步地实现接下来要学习的各种功能。