官网对生命周期给出了一个比较完成的流程图,如下所示:

从图中我们可以看到我们的Vue创建的过程要经过以下的钩子函数:


beforeCreate => created => beforeMount => mounted
=> beforeUpdate => updated
=> beforeDestroy => destroyed

那么我们就从源码的角度来看一看吧,当我们new Vue的时候,会执行_init函数


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函数如下


export function initMixin (Vue: Class<Component>) {
Vue.prototype._init = function (options?: Object) {
....
以下就是进行了生命周期
vm._self = vm
// 首先进行初始化生命周期的参数
initLifecycle(vm)
// 在初始化事件
initEvents(vm)
// 初始化render
initRender(vm)
// 开始调用beforeCreate钩子函数,和图中的流程图一样
callHook(vm, 'beforeCreate')
// 之后开始初始化变量等一些数据
initInjections(vm) // resolve injections before data/props
initState(vm)
initProvide(vm) // resolve provide after data/props
// 开始调用created钩子函数
callHook(vm, 'created') /* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
vm._name = formatComponentName(vm, false)
mark(endTag)
measure(`vue ${vm._name} init`, startTag, endTag)
} if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
}
}

以上init函数我们已经看到了beforeCreate和created,那么callHook是怎么调用的钩子函数呢?


export function callHook (vm: Component, hook: string) {
// #7573 disable dep collection when invoking lifecycle hooks
pushTarget()
// 从$options里拿到钩子函数
const handlers = vm.$options[hook]
if (handlers) {
for (let i = 0, j = handlers.length; i < j; i++) {
try {
// 然后再调用
handlers[i].call(vm)
} catch (e) {
handleError(e, vm, `${hook} hook`)
}
}
}
if (vm._hasHookEvent) {
vm.$emit('hook:' + hook)
}
popTarget()
}

这边就会有几个问题:
从vm.$options[hook]中取钩子函数,那个这个钩子函数是哪来来的? 为了拿到的钩子函数是个数组?我们平时使用不都是只是写个函数吗?

我们可以看到在$options是在下面_init中进行合并的


Vue.prototype._init = function(){
...
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options || {},
vm
)
...
} export const LIFECYCLE_HOOKS = [
'beforeCreate',
'created',
'beforeMount',
'mounted',
'beforeUpdate',
'updated',
'beforeDestroy',
'destroyed',
'activated',
'deactivated',
'errorCaptured'
]

我们可以看到钩子函数一开始就已经在vue内部已经定义好了,并且还有几个钩子函数不是实话化实例的使用执行的。而是对keep-alive组件配合使用的activated,deactivated。以及错误抛出钩子函数errorCaptured
然后再根据这些内部定义的钩子函数和传入的参数进行合并

那么为什么钩子函数是数组呢?这个其实很简单是因为vue内部也需要执行一些函数,顾把函数也放到钩子函数里。所以需要数组遍历。

所以这些所谓的钩子函数就是一个回调函数。

其余几个钩子函数也是在需要调用的时候使用callHook(vm, 'xxx')来执行

如果对您有帮助请点个赞,谢谢!

原文地址:https://segmentfault.com/a/1190000016906255

Vue源码学习(二)——生命周期的更多相关文章

  1. Vue源码学习二 ———— Vue原型对象包装

    Vue原型对象的包装 在Vue官网直接通过 script 标签导入的 Vue包是 umd模块的形式.在使用前都通过 new Vue({}).记录一下 Vue构造函数的包装. 在 src/core/in ...

  2. vue 源码学习二 实例初始化和挂载过程

    vue 入口 从vue的构建过程可以知道,web环境下,入口文件在 src/platforms/web/entry-runtime-with-compiler.js(以Runtime + Compil ...

  3. Vue源码学习(二)$mount() 后的做的事(1)

    Vue实例初始化完成后,启动加载($mount)模块数据. (一)Vue$3.protype.$mount             标红的函数 compileToFunctions 过于复杂,主要是生 ...

  4. Vue源码学习三 ———— Vue构造函数包装

    Vue源码学习二 是对Vue的原型对象的包装,最后从Vue的出生文件导出了 Vue这个构造函数 来到 src/core/index.js 代码是: import Vue from './instanc ...

  5. 手牵手,从零学习Vue源码 系列二(变化侦测篇)

    系列文章: 手牵手,从零学习Vue源码 系列一(前言-目录篇) 手牵手,从零学习Vue源码 系列二(变化侦测篇) 陆续更新中... 预计八月中旬更新完毕. 1 概述 Vue最大的特点之一就是数据驱动视 ...

  6. Vue源码学习1——Vue构造函数

    Vue源码学习1--Vue构造函数 这是我第一次正式阅读大型框架源码,刚开始的时候完全不知道该如何入手.Vue源码clone下来之后这么多文件夹,Vue的这么多方法和概念都在哪,完全没有头绪.现在也只 ...

  7. Vue源码分析(二) : Vue实例挂载

    Vue源码分析(二) : Vue实例挂载 author: @TiffanysBear 实例挂载主要是 $mount 方法的实现,在 src/platforms/web/entry-runtime-wi ...

  8. Dubbo源码学习(二)

    @Adaptive注解 在上一篇ExtensionLoader的博客中记录了,有两种扩展点,一种是普通的扩展实现,另一种就是自适应的扩展点,即@Adaptive注解的实现类. @Documented ...

  9. 最新 Vue 源码学习笔记

    最新 Vue 源码学习笔记 v2.x.x & v3.x.x 框架架构 核心算法 设计模式 编码风格 项目结构 为什么出现 解决了什么问题 有哪些应用场景 v2.x.x & v3.x.x ...

  10. 【Vue源码学习】依赖收集

    前面我们学习了vue的响应式原理,我们知道了vue2底层是通过Object.defineProperty来实现数据响应式的,但是单有这个还不够,我们在data中定义的数据可能没有用于模版渲染,修改这些 ...

随机推荐

  1. Xshell配色方案啊【学习笔记】

    自己移植从putty版本移植到Xshell的配色方案,效果不错,看上去挺舒服. [myisayme] text(bold)=eaeaea magenta(bold)=ff55ff text=fffff ...

  2. bzoj 2044 三维导弹拦截 —— 最小路径覆盖

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2044 第一问暴力 n^2 即可: 注意这道题对位置没要求!所以先按第一维排序一下即可: 然后 ...

  3. Java Swing Action 动作

    Swing包提供了一种非常实用的机制来封装命令,并将它们连接到多个事件源,这就是Action接口.一个动作是一个封装下列内容的对象: × 命令的说明(一个文本字符串和一个可选图标): × 执行命令所需 ...

  4. bzoj4889

    http://www.lydsy.com/JudgeOnline/problem.php?id=4889 人傻常数大 bzoj上跑不过 洛谷上能过两到三个点 我写的是树套树啊 怎么跑的比分块还慢 每次 ...

  5. 对RDD分区的理解

    举个例子: val logFile = "file:///home/soyo/桌面/6.txt" val conf = new SparkConf().setAppName(&qu ...

  6. 常见的几种异常类型Exception

    转自:https://blog.csdn.net/niceworkgogogo/article/details/71746208 算数异常类:ArithmeticExecption 空指针异常类型:N ...

  7. Reward(toposort)

    http://acm.hdu.edu.cn/showproblem.php?pid=2647 #include <stdio.h> #include <string.h> #i ...

  8. [Apple开发者帐户帮助]八、管理档案(4)

    您可以编辑,下载或删除在开发人员帐户中创建的配置文件.例如,如果您撤消了证书或禁用了配置文件中包含的设备,请编辑配置文件.或重新置备的个人资料,如果因为你它是无效的功能的应用程式服务. 注意: Xco ...

  9. VUE修改每个页面title

    //index.js routes: [ { name:'home', path: '/home/:openname', component: Home, meta: { title: '首页' } ...

  10. PHP富文本编辑器 之Kindeditor的使用 一

    一.下载编辑器源码 KindEditor 4.1.10 (2013-11-23) [1143KB] 下载页面: http://kindeditor.net/down.php 二.部署编辑器 将下载文件 ...