显微镜下的webpack4:灵魂tapable,终于搞懂钩子系列! (2)

从上述我们可以看到通过主演剧情了解到各种同步钩子的用法,可能难以理解就是熔断型的钩子,这个钩子的存在意义就是,可以中断一系列的事情,比如有地方出错了,或者不需要进行下一步的操作我们就可以及时结束。

那么如果我们做的事情都是异步的,每一个事件之间都有联系,那么我们就不能用同步的方法了。这个时候我们可以将sync钩子替换成async的钩子。

async相对于sync多了一个callback的机制,就是这样的:

this.hooks.beforeWork.tapAsync("putOnCloth",(params,callback)=>{ console.log("穿衣服!") callback();//此处无callback,则getOut这个挂载的函数便不会运行 }) this.hooks.beforeWork.tapAsync("getOut",(params,callback)=>{ console.log("出门!") callback()//此处无callback,则beforeWork这个钩子的回调函数不会执行 }) this.hooks.beforeWork.callAsync("working",err=>{ console.log(err+" end!")//如果最后一个tap的函数没有callback则不会执行 })

这里我们可以将callback当作next函数,也就是下一个tap的函数的意思。以及如果当前tap的函数报错,则可以在callback中加入错误的原因,那么接下来的函数便不会运行,也就是这样callback("errorReason"),那么就直接回调用当前钩子的callAsync绑定的函数。

this.hooks.beforeWork.tapAsync("putOnCloth",(params,callback)=>{ console.log("穿衣服!") callback("error");此处加入了错误原因,那么直接callAsync,抛弃了getOut }) this.hooks.beforeWork.tapAsync("getOut",(params,callback)=>{//直接skip了 console.log("出门!") }) this.hooks.beforeWork.callAsync("working",err=>{ console.log(err+" end!")//error end!直接打出错误原因。 }) 小tips

大家发现没有,Async和sync的区别在于Async通过callback来和后续的函数沟通,sync则是通过return一个值来做交流。所以,Async自带sync中bail类型的钩子。我曾经做了一个无聊的统计,因为钩子太多了,我写了一个代码遍历了webpack这个项目,得出了所有钩子的使用情况,结果如下所示:

SyncHook 69 SyncBailHook 63 SyncWaterfallHook 36 SyncLoopHook 0 AsyncParallelHook 1 AsyncParallelBailHook 0 AsyncSeriesHook 14 AsyncSeriesBailHook 0 AsyncSeriesWaterfallHook 5

但是我发现AsyncSeriesBailHook竟然是0的时候,我很震惊,现在知道原因了,因为从作用上来说他和异步钩子的共能本身就重叠了,所以同理AsyncParallelBailHook这个平行执行的bail类型的钩子也是0 。bail在Async中功能重复,因次用的很少。

言归正传,既然AsyncSeriesHook的callback通过第一个err参数来判断是否异步成功,不成功则直接callAsync回调。那么water类型的该如何传递参数?我们都知道water和basic的区别就在于basic每个异步tap之间并无参数传递,而water则是参数传递。很简单,在err后面再加一个参数,作为下一个tap的传入值。

this.hooks.atWork.tapAsync("makePPT",(work,callback)=>{ console.log("做PPT!") callback("没做完 ","你的ppt")//第一个参数是err,上交你的报错,第二个参数是你自定义要下一个tap处理的参数。如果有err,则忽略此参数。 }) this.hooks.atWork.tapAsync("meeting",(work,callback)=>{//因为ppt没做完,所以开不了会 console.log("带着"+work+"开会!") callback() }) this.hooks.atWork.callAsync("working",err=>{//没做完来这里领罚了。 console.log(err+" end!") }) 支线剧情

我们的日常生活!才不会这么单调,怎么会一路顺顺利利地走下来呢?每天都有不同的精彩啊!小插曲肯定少不了。

那么我们就要相办法将支线剧情插入主线剧情之中了。这个时候一个MyDaily的类已经放不下我们的精彩生活了。

以下班之后的精彩为例,我们不一定会直接回家也有可能约会蹦迪什么的。所以这里我们new一个名为Activity的类。假设我们的夜生活有两个活动,一个派对活动,一个回家。那么派对活动肯定有个流程,我们就用熔断型的,为什么呢!不开心了接下来就都别执行了!回家吧!回家的这个活动就是简单的钩子。

class Activity { constructor() { this.hooks = { goParty:new SyncBailHook(), goHome:new SyncHook() }; } prepare(){ this.hooks.goParty.tap("happy",()=>{ console.log("happy party") }) this.hooks.goParty.tap("unhappy",()=>{ console.log("unhappy") return "go home" }) this.hooks.goParty.tap("play",()=>{ console.log("continue playing") }) this.hooks.goHome.tap("goHome",()=>{ console.log("I'm going to sleep") }) } start(){ this.hooks.goParty.call() this.hooks.goHome.call() } }

然后我们要将这个单独的类挂到MyDaily的下面,毕竟这也是日常的一部分虽然非正式关卡。我们可以在工作结束自开始准备晚上的活动,等到一下班就开始我们丰富的夜生活。这个时候我们可以在钩子的回调函数中触发另一个类中的钩子状态,激活或着运行。

class MyDaily { constructor() { this.hooks = { .... }; this.activity=new Activity()//实例化Activity } run(){ ... this.hooks.atWork.callAsync("working",res=>{ this.activity.prepare()//下班了大家可以躁动起来了 }) this.hooks.afterWork.callAsync("activity",err=>{ this.activity.start()//去浪咯! }) } } 总结

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpgyxx.html