webpack核心模块tapable源码解析 (5)

到这里,tapable的源码架构和基本实现我们已经弄清楚了,但是本文只用了SyncHook和SyncBailHook做例子,其他的,比如AsyncParallelHook并没有展开讲。因为AsyncParallelHook之类的其他Hook的实现思路跟本文是一样的,比如我们可以先实现一个独立的AsyncParallelHook类:

class AsyncParallelHook { constructor(args = []) { this._args = args; this.taps = []; } tapAsync(name, task) { this.taps.push(task); } callAsync(...args) { // 先取出最后传入的回调函数 let finalCallback = args.pop(); // 定义一个 i 变量和 done 函数,每次执行检测 i 值和队列长度,决定是否执行 callAsync 的最终回调函数 let i = 0; let done = () => { if (++i === this.taps.length) { finalCallback(); } }; // 依次执行事件处理函数 this.taps.forEach(task => task(...args, done)); } }

然后对他的callAsync函数进行抽象,将其抽象到代码工厂类里面,使用字符串拼接的方式动态构造出来就行了,整体思路跟前面是一样的。具体实现过程可以参考tapable源码:

Hook类源码

SyncHook类源码

SyncBailHook类源码

HookCodeFactory类源码

总结

本文可运行示例代码已经上传GitHub,大家拿下来一边玩一边看文章效果更佳:https://github.com/dennis-jiang/Front-End-Knowledges/tree/master/Examples/Engineering/tapable-source-code

下面再对本文的思路进行一个总结:

tapable的各种Hook其实都是基于发布订阅模式。

各个Hook自己独立实现其实也没有问题,但是因为都是发布订阅模式,会有大量重复代码,所以tapable进行了几次抽象。

第一次抽象是提取一个Hook基类,这个基类实现了初始化和事件注册等公共部分,至于每个Hook的call都不一样,需要自己实现。

第二次抽象是每个Hook在实现自己的call的时候,发现代码也有很多相似之处,所以提取了一个代码工厂,用来动态生成call的函数体。

总体来说,tapable的代码并不难,但是因为有两次抽象,整个代码架构显得不那么好读,经过本文的梳理后,应该会好很多了。

文章的最后,感谢你花费宝贵的时间阅读本文,如果本文给了你一点点帮助或者启发,请不要吝啬你的赞和GitHub小星星,你的支持是作者持续创作的动力。

欢迎关注我的公众号进击的大前端第一时间获取高质量原创~

“前端进阶知识”系列文章:https://juejin.im/post/5e3ffc85518825494e2772fd

“前端进阶知识”系列文章源码GitHub地址: https://github.com/dennis-jiang/Front-End-Knowledges

QR1270

参考资料

tapable用法介绍:https://www.cnblogs.com/dennisj/p/14538668.html

tapable源码地址:https://github.com/webpack/tapable

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

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