最近在公众号tecvan学习webpack源码,想要读明白webpack源码,tapable是绕不开的,这篇文章主要介绍tapable的回掉类型,代码结构,实现原理,事件发布订阅的插件结构。
tapable是事件订阅发布模式。基本使用方法使用如下
发布订阅模式较为简单,但是思考一下问题:
1, 如果事件订阅者比较多,并且这些订阅者是有执行顺序的?
2, 后面的订阅者想在前面的订阅者前面执行这么办?
3, 订阅者流程如果需要打断机制怎么实现例如(SyncBailHook:如果一个订阅者的返回值非undefined,就打断执行流)
4, 如果需要上一个订阅者的返回值是下一个订阅者的入参,怎么办?
5, 上面的4个问题如果订阅者是异步函数需要怎么做?
可以总结为执行流程控制,可以思考最简单的一个,都是同步函数,并且先不用对这些订阅者排序。简单示意代码如下:
如果在执行流程中只要有一个函数的返回值为非空就打断执行流程tapable叫Bail类型,一个订阅者的返回值是下一个订阅者的入参tapable叫waterful,执行每一个订阅者直到该订阅者的返回值为undefined叫loop。根据上面的代码上面的三种类型实现起来都很简单。思考一下这三种执行方式如果是异步函数需要怎么处理呢?当然异步平行执行时好处理的代码如下:
如果想让订阅者同步执行示意代码如下:
仔细观察这段代码,正好能构成循环。怎么让代码按我们设定好的这种顺序和方法执行呢?我们怎么把所有的代码都抽象出来,都封装一下,让代码按照我们设定的方式执行呢,我们可以生成新的代码,让订阅者函数让我们配置的方式执行,tapable使用的就是代码生成器。先来看一段tapable生成的代码AsyncParallelBailHook类的代码:
仔细看一下是不是和我们的示意代码逻辑大致相同。那接下来就是怎么生成代码的过程了。我们先实现一个最简单的同步函数的Bail执行(SyncBailHook),代码如下:
这是SyncBailHook的简单实现,SyncWaterfallHook的简单实现,只要将上一个函数的返回值,传递到下一个函数就行了。下面看看tapable的实现类型:
看着比较多按执行流程两类Serise一个一个执行,Paralle平行执行,函数间的关系是我们上面谈到的三种Bail,weaterful,loop,所有的方式都是他们的组合,tapable的代码结构如图:
和我们上面的实现大致是一样的。有兴趣的同学可以实现以下SyncWaterfallHook,和其他Hooks,现在回到刚才的问题,怎么让函数按照配置的顺序执行呢?例如,有三个钩子函数,定义的第三个钩子函数想在第一个钩子函数执行后执行应该怎么做呢?tapable在配置的时候会有before字段,在初始化的过程中会根据这两个字段对所有的钩子函数进行排序,排序的核心代码如下:
核心思路是每增加一个钩子函数就把它放到执行队列里,根据before字段对队列里的函数进行重新排序,然后钩子队列就按照我们定义的顺序执行了,这种插入的排序方式可以学习一下。以上就是整个tapable的实现逻辑,感谢观看。