执行生命周期钩子函数beforeCreate
callHook(vm,'beforeCreate')
讲了这么久,终于到了生命周期函数这一节。其主要逻辑都集中在callHook
方法中,我们先来看下这个函数里都有些啥,源码位置:src/core/instance/lifecycle.js
exportfunctioncallHook(vm:Component,hook:string){pushTarget()consthandlers=vm.$options[hook]constinfo=`${hook}hook`if(handlers){for(leti=0,j=handlers.length;i<j;i++){invokeWithErrorHandling(handlers[i],vm,null,vm,info)}}if(vm._hasHookEvent){vm.$emit('hook:'+hook)}popTarget()}
首先在讲解原理之前,我们看到callHook
函数头尾分别执行了pushTarget()
、popTarget()
方法,这么做是为了防止在执行生命周期钩子函数中重复定义响应式数据。然后再回顾一下之前$options
合并一节中生命周期策略合并方法,最终生命周期钩子函数合并后的结果一定是数组格式。
从当前实例配置中找到生命周期钩子函数同名数组;
若存在,则遍历当前数组中的方法,依次执行;
invokeWithErrorHandling
函数可能会让大家有点迷惑,其实就是函数的call
或者apply
额外封装了一些异常情况,若有异常则直接打印问题。 接下来看下invokeWithErrorHandling
函数:
exportfunctioninvokeWithErrorHandling(handler:Function,context:any,args:null|any[],vm:any,info:string){letrestry{res=args?handler.apply(context,args):handler.call(context)if(res&&!res._isVue&&isPromise(res)&&!res._handled){res.catch(e=>handleError(e,vm,info+`(Promise/async)`))//issue#9511//avoidcatchtriggeringmultipletimeswhennestedcallsres._handled=true}}catch(e){handleError(e,vm,info)}returnres}
我们看到首先用try..catch...
包裹起来,若出现异常则直接打印。根据第三个参数args
是否数组,选择使用call
还是apply
调用执行函数。若传进来的第一个参数handler
是Promise
类型,增加catch
捕获异常并打印出来。 一句话总结:生命周期钩子执行就是遍历钩子函数数组,依次执行其中的方法。