webpack核心模块tapable用法解析 (3)

image-20210309163514680

异步API

所谓异步API是相对前面的同步API来说的,前面的同步API的所有回调都是按照顺序同步执行的,每个回调内部也全部是同步代码。但是实际项目中,可能需要回调里面处理异步情况,也可能希望多个回调可以同时并行执行,也就是Parallel。这些需求就需要用到异步API了,主要的异步API就是这些:

const { AsyncParallelHook, AsyncParallelBailHook, AsyncSeriesHook, AsyncSeriesBailHook, AsyncSeriesWaterfallHook } = require("tapable");

既然涉及到了异步,那肯定还需要异步的处理方式,tapable支持回调函数和Promise两种异步的处理方式。所以这些异步API除了用前面的tap来注册回调外,还有两个注册回调的方法:tapAsync和tapPromise,对应的触发事件的方法为callAsync和promise。下面分别来看下每个API吧:

AsyncParallelHook

AsyncParallelHook从前面介绍的命名规则可以看出,他是一个异步并行执行的Hook,我们先用tapAsync的方式来看下怎么用吧。

tapAsync和callAsync

还是那个小汽车加速的例子,只不过这个小汽车加速没那么快了,需要一秒才能加速完成,然后我们在2秒的时候分别检测是否超速和是否损坏,为了看出并行的效果,我们记录下整个过程从开始到结束的时间:

const { AsyncParallelHook } = require("tapable"); const accelerate = new AsyncParallelHook(["newSpeed"]); console.time("total time"); // 记录起始时间 // 注意注册异步事件需要使用tapAsync // 接收的最后一个参数是done,调用他来表示当前任务执行完毕 accelerate.tapAsync("LoggerPlugin", (newSpeed, done) => { // 1秒后加速才完成 setTimeout(() => { console.log("LoggerPlugin", `加速到${newSpeed}`); done(); }, 1000); }); accelerate.tapAsync("OverspeedPlugin", (newSpeed, done) => { // 2秒后检测是否超速 setTimeout(() => { if (newSpeed > 120) { console.log("OverspeedPlugin", "您已超速!!"); } done(); }, 2000); }); accelerate.tapAsync("DamagePlugin", (newSpeed, done) => { // 2秒后检测是否损坏 setTimeout(() => { if (newSpeed > 300) { console.log("DamagePlugin", "速度实在太快,车子快散架了。。。"); } done(); }, 2000); }); accelerate.callAsync(500, () => { console.log("任务全部完成"); console.timeEnd("total time"); // 记录总共耗时 });

上面代码需要注意的是,注册回调要使用tapAsync,而且回调函数里面最后一个参数会自动传入done,你可以调用他来通知tapable当前任务已经完成。触发任务需要使用callAsync,他最后也接收一个函数,可以用来处理所有任务都完成后需要执行的操作。所以上面的运行结果就是:

image-20210309171527773

从这个结果可以看出,最终消耗的时间大概是2秒,也就是三个任务中最长的单个任务耗时,而不是三个任务耗时的总额,这就实现了Parallel并行的效果。

tapPromise和promise

现在都流行Promise,所以tapable也是支持的,执行效果是一样的,只是写法不一样而已。要用tapPromise,需要注册的回调返回一个promise,同时触发事件也需要用promise,任务运行完执行的处理可以直接使用then,所以上述代码改为:

const { AsyncParallelHook } = require("tapable"); const accelerate = new AsyncParallelHook(["newSpeed"]); console.time("total time"); // 记录起始时间 // 注意注册异步事件需要使用tapPromise // 回调函数要返回一个promise accelerate.tapPromise("LoggerPlugin", (newSpeed) => { return new Promise((resolve) => { // 1秒后加速才完成 setTimeout(() => { console.log("LoggerPlugin", `加速到${newSpeed}`); resolve(); }, 1000); }); }); accelerate.tapPromise("OverspeedPlugin", (newSpeed) => { return new Promise((resolve) => { // 2秒后检测是否超速 setTimeout(() => { if (newSpeed > 120) { console.log("OverspeedPlugin", "您已超速!!"); } resolve(); }, 2000); }); }); accelerate.tapPromise("DamagePlugin", (newSpeed) => { return new Promise((resolve) => { // 2秒后检测是否损坏 setTimeout(() => { if (newSpeed > 300) { console.log("DamagePlugin", "速度实在太快,车子快散架了。。。"); } resolve(); }, 2000); }); }); // 触发事件使用promise,直接用then处理最后的结果 accelerate.promise(500).then(() => { console.log("任务全部完成"); console.timeEnd("total time"); // 记录总共耗时 });

这段代码的逻辑和运行结果和上面那个是一样的,只是写法不一样:

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

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