跳到主要内容

官方实现

2023年06月11日
柏拉文
越努力,越幸运

一、src/core/instance/lifecycle.ts callHook()


/**
* callHook(vm, 'mounted')
* 执行实例指定的生命周期钩子函数
* 如果实例设置有对应的 Hook Event,比如:<comp @hook:mounted="method" />,执行完生命周期函数之后,触发该事件的执行
* @param {*} vm 组件实例
* @param {*} hook 生命周期钩子函数
*/

export function callHook(
vm: Component,
hook: string,
args?: any[],
setContext = true
) {
// 在执行生命周期钩子函数期间禁止依赖收集
pushTarget()
const prev = currentInstance
setContext && setCurrentInstance(vm)
// 从实例配置对象中获取指定钩子函数,比如 mounted
const handlers = vm.$options[hook]
const info = `${hook} hook`
if (handlers) {
// 通过 invokeWithErrorHandler 执行生命周期钩子
for (let i = 0, j = handlers.length; i < j; i++) {
invokeWithErrorHandling(handlers[i], vm, args || null, vm, info)
}
}
// Hook Event,如果设置了 Hook Event,比如 <comp @hook:mounted="method" />,则通过 $emit 触发该事件
// vm._hasHookEvent 标识组件是否有 hook event,这是在 vm.$on 中处理组件自定义事件时设置的
if (vm._hasHookEvent) {
// vm.$emit('hook:mounted')
vm.$emit('hook:' + hook)
}
setContext && setCurrentInstance(prev)
// 关闭依赖收集
popTarget()
}

二、src/core/util/error.ts invokeWithErrorHandling()


/**
* 通用函数,执行指定函数 handler
* 传递进来的函数会被用 try catch 包裹,进行异常捕获处理
*/
export function invokeWithErrorHandling(
handler: Function,
context: any,
args: null | any[],
vm: any,
info: string
) {
let res
try {
// 执行传递进来的函数 handler,并将执行结果返回
res = args ? handler.apply(context, args) : handler.call(context)
if (res && !res._isVue && isPromise(res) && !(res as any)._handled) {
res.catch(e => handleError(e, vm, info + ` (Promise/async)`))
// issue #9511
// avoid catch triggering multiple times when nested calls
;(res as any)._handled = true
}
} catch (e: any) {
handleError(e, vm, info)
}
return res
}