从Vue生命周期谈Hook

本文深入探讨了Hook机制在软件开发中的应用,从Git的webhook到Vue的生命周期钩子,揭示了Hook作为回调函数的一种高级形式如何增强代码的可扩展性和解耦特性。

前言

接触hook是从webhook开始接触的,webhookgit的一个扩展服务,可以在仓库接收到push/commit事件并发送http request至一个开发者可以自定义的URL

通过这个,我们可以在服务器实现若干自动化流程(诸如更新最新代码,打包编译,部署)

webhook的技术原理,是来自于githook机制,简单来说,githook机制是 在一些常用的git 命令之后去触发一些开发者自定义的脚本(这些脚本存在于本地,在.git/hooks下)

如下图:

  • git-hook 提供统一接口
  • 开发者根据接口去写脚本
  • webhook只是别人写好的脚本,当然自己也可以写(可以不是发送请求)

git-hook 伪代码

个人认为hook会按照如下伪代码去实现

received 'commit' event // 接受到commit事件

...一些commit的执行代码

if('pre-commit.sh' exist){
	trigger 'pre-commit.sh' // 触发pre-commit脚本
}

emit 'commited' // 完成commit的标志

pre-commit这个状态是由git本身所定义的,它会在commit事件执行前去执行一个脚本(如果这个脚本存在),而这个脚本是开发者自己写的。当然你可以理解为

  • 脚本最开始存在,只不过内容为空
  • 开发者补充脚本内容实现自定义功能

从Vue源码看Hook

Vue的各生命周期,其实就是Vue开发者规定的一些hook,和git里面规定的hook类似,你只要往hook里面填自定义内容,它就可以执行。如vue实例里的beforeCreate,created,mounted等,都是hook

简单来说,hook其实就是一种回调函数,只不过这种回调函数的名称已经被固定,内容不固定,且函数名称作为了一个接口被暴露出去。这样也更好了进行了抽。经常变化的内容抽象暴露出去,将固定不变的代码进行封装。

假如Vue生命周期没有设计Hook,那么自定义的一些业务逻辑将深深与框架本身耦合,也就是说,你要在框架内部去写业务逻辑。

Vue生命周期中Hook源码浅析

在vue源码的/src/core/instance/lifecycle.js,有Vue声明周期的定义和hook的实现callHook方法是触发hook之后的执行函数:

  • 第一个参数vm是传入的vue实例,handlers选取的vue实例里关于特定hook的所有方法。这里简单猜测一下vm.$options中的内容
vm.$options = {
	'beforeCreate':[
		function a (){},
		function b (){},
		... // a,b均是自己在实例里面定义的
	],
	'created':[],
	'beforeMount':[],
	'mounted':[]
	....
}

遍历handlers将会遍历出在指定生命周期里开发者定义的不同方法,handler[i].call(vm)则是在vm的上下分环境下去执行handler[i]

  • 第二个参数则是上文提到的指定的hook string,诸如beforeCreate,created,beforeMount,mounted...

接下来,我们再看下在哪里调用的callHook

同样在/src/core/instance/lifecycle.js里:

在不同的生命周期执行函数都执行了一次callHook,那么如果开发者在实例中的指定生命周期内定义了方法,这些方法就会在callHook里被执行(以实例的上下文)

总结

HOOK是一个非常好的设计,据说来源于Liunx操作系统设计,从GitVue,都能找到HOOK的影子,特别是对于JavaScript这门以事件驱动的单线程语言里,更为适用。

仔细想想JQuery里:

$.ajax({
	method:'GET',
	URL:'http://*****',
	data:{},
	success:()=>{},
	fail:()=>{}
})

里面的sucessfail方法会在xhr回调后执行,这也是一种hook,为了方便理解,你可以将hook理解为callBackFunction(回调函数)。但是实际hook应用里面,回调函数函数名和函数实现细节已经被抽象暴露出来进行单独维护和修改。这一点极大增强了可扩展性




 

### Vue.js 生命周期详解 #### 1. `beforeCreate` 阶段 在 `beforeCreate` 阶段,Vue 实例刚刚被创建,此时数据观测 (data observer)、事件配置以及 `$el` 属性都尚未初始化。这意味着在这个阶段无法访问到 `data` 或者 `methods` 中的内容[^3]。 #### 2. `created` 阶段 当进入 `created` 阶段时,Vue 实例已经完成了数据的初始化工作,可以在此处访问并操作 `data` 和 `methods` 的内容。此阶段通常用来发起网络请求或者处理一些不依赖于 DOM 的逻辑。 #### 3. `beforeMount` 阶段 在 `beforeMount` 阶段,模板已经被编译成虚拟 DOM 树,但是还未挂载到实际的 DOM 上。如果需要在挂载之前对虚拟 DOM 进行最后的操作,可以在这一阶段实现。 #### 4. `mounted` 阶段 一旦到达 `mounted` 阶段,意味着组件已被成功挂载至真实 DOM 并可正常显示给用户。这是最常用的生命周期钩子之一,适合执行与 DOM 相关的任务,例如设置定时器、绑定第三方库或启动动画效果等。此外,这也是一个理想的位置去发送 AJAX 请求以加载初始数据[^4]。 ```javascript new Vue({ el: '#app', data() { return { message: 'Hello!' }; }, mounted() { console.log('Component has been mounted.'); // Example of an API call inside the mounted hook. fetch('/api/data') .then(response => response.json()) .then(data => this.message = data); } }); ``` #### 5. `beforeUpdate` 阶段 每当数据发生变化触发重新渲染流程时会先调用 `beforeUpdate` 方法。在这里你可以捕获即将发生的变化但还没反映到视图上的状态变化情况。 #### 6. `updated` 阶段 经过重绘后即刻触发的是 `updated` 函数,在这里能够确保所有的更改都已经同步到了对应的 UI 元素上。然而需要注意避免在此期间修改任何引起新一次更新循环的状态变量以免造成无限递归的情况。 #### 7. `beforeDestroy` / `beforeUnmount` 阶段 当组件即将被移除的时候会先进入 `beforeDestroy` (在 Vue 3.x 版本中更名为 `beforeUnmount`),这提供了一个机会让我们去做必要的清理动作比如清除计时器或是解除某些订阅关系等等^. #### 8. `destroyed` / `unmounted` 阶段 最后一个重要的周期就是 `destroyed`(同样对应 Vue 3.x 的 `unmounted`)。至此为止,该实例完全消失不再存在;它所关联的所有东西也都随之释放掉了——包括监听器、子组件以及其他资源. 通过合理利用上述各个不同的生命週期挂钩点,我们可以更精确地控制我们的应用行为,并且优化性能表现。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值