Tapable 类似于 emimt ,是一个专注于事件流的库。tapable 还允许通过回调参数访问事件的发起者和响应者。
内部支持9种类型的执行hook
const {SyncHook, //串行执行, 不关心返回值。SyncBailHook,//串行执行,有一个返回值不为null ,则停止执行后续事件。SyncWaterfallHook,// 串行执行,返回值会被传递,并被加起来。SyncLoopHook,//串行循环执行,只要还有一个返回值是 undefined 就会持续循环全部事件,直到最后一个返回值为no-undefined则立即结束。AsyncParallelHook,//并行执行AsyncParallelBailHook,AsyncSeriesHook,AsyncSeriesBailHook,AsyncSeriesWaterfallHook} = require("tapable");
Async
SyncHook
串行执行, 不关心返回值。
var {SyncHook} = require("tapable")const hook = new SyncHook(["name", "age"]);hook.tap('1',(name,age)=>{console.log(name,1)})hook.tap('2',(name,age)=>{console.log(name,2)})hook.call('GMX')//"GMX" 1//"GMX" 2
SyncBailHook
串行执行,有一个返回值不为undefined,则停止执行后续事件。
var tapable = require("tapable")const hook = new tapable.SyncBailHook(["name", "age"]);hook.tap('1',(name,age)=>{console.log(name+1)return 'GG'})hook.tap('2',(name,age)=>{console.log(name+2)})console.log('return:' + hook.call('GMX'))//"GMX1"//"return:GG"
SyncWaterfallHook
串行执行,返回值会被传递,并被加起来。
var tapable = require("tapable")const hook = new tapable.SyncWaterfallHook(["name", "age"]);hook.tap('1',(name,age)=>{console.log(name+1)return 1})hook.tap('2',(name,age)=>{console.log(name+2)return 2})console.log('return:' + hook.call('GMX'))//GMX1//3//return:2
SyncLoopHook
串行循环执行,循环执行所有返回值不为 undefined 的事件,直到所有返回值都是undefined。
var tapable = require("tapable")var count = 0;const hook = new tapable.SyncLoopHook(["name", "age"]);hook.tap('1',(name,age,res)=>{console.log(name+'_'+count+'_'+1)if(count > 2){return undefined}count ++return 1})hook.tap('2',(name,age,res)=>{console.log(name+'_'+count+'_'+2)if(count > 3){return undefined}count ++return 2})hook.tap('3',(name,age,res)=>{console.log(name+'_'+count+'_'+2)if(count > 4){return undefined}count ++return 3})console.log('return:' + hook.call('GMX'))//GMX_0_1//GMX_1_1//GMX_2_1//GMX_3_1//GMX_3_2//GMX_4_1//GMX_4_2//GMX_4_2//GMX_5_1//GMX_5_2//GMX_5_2//return:undefined
Async
async 异步事件支持两种事件模式,callback + promise。
AsyncParallelHook
并行异步执行,第一个事件回调之后,就会调用总的回调,但是事件会执行完成。返回第一个执行完成的值。
var tapable = require("tapable")const hook = new tapable.AsyncParallelHook(["name", "age"]);hook.tapAsync('3',(name,age,callback)=>{setTimeout(()=>{console.log(name+3)callback('c3')},3000)})hook.tapAsync('1',(name,age,callback)=>{setTimeout(()=>{console.log(name+1)callback('c1')},1000)})hook.tapAsync('2',(name,age,callback)=>{setTimeout(()=>{console.log(name+2)callback('c2')},2000)})hook.callAsync('GMX','18',(res)=>{console.log('res:'+res);})//"GMX1"//"res:c1"//"GMX2"//"GMX3"
AsyncParallelBailHook
并行异步执行,等待所有都执行完成才会回调结束。返回最后一个值。
var tapable = require("tapable")const hook = new tapable.AsyncParallelBailHook(["name", "age"]);hook.tapPromise('3',(name,age)=>{return new Promise((reslove,reject)=>{setTimeout(()=>{console.log(name+3)reslove('c3')},3000)})})hook.tapPromise('1',(name,age)=>{return new Promise((reslove,reject)=>{setTimeout(()=>{console.log(name+1)reslove('c1')},1000)})})hook.tapPromise('2',(name,age)=>{return new Promise((reslove,reject)=>{setTimeout(()=>{console.log(name+2)reslove('c2')},2000)})})hook.promise('GMX','18').then((res)=>{console.log('res:'+res);})//"GMX1"//"GMX2"//"GMX3"//"res:c3"
AsyncSeriesHook
串行异步执行,所有都执行结束后返回,无返回值。
var tapable = require("tapable")const hook = new tapable.AsyncSeriesHook(["name", "age"]);hook.tapPromise('3',(name,age)=>{return new Promise((reslove,reject)=>{setTimeout(()=>{console.log(name+3)reslove('c3')},3000)})})hook.tapPromise('1',(name,age)=>{return new Promise((reslove,reject)=>{setTimeout(()=>{console.log(name+1)reslove('c1')},1000)})})hook.tapPromise('2',(name,age)=>{return new Promise((reslove,reject)=>{setTimeout(()=>{console.log(name+2)reslove('c2')},2000)})})hook.promise('GMX','18').then((res)=>{console.log('res:'+res);})//"GMX3"//"GMX1"//"GMX2"//"res:undefined"
AsyncSeriesHook
异步串行执行,一个结束即结束
var tapable = require("tapable")const hook = new tapable.AsyncSeriesHook(["name", "age"]);hook.tapPromise('1',(name,age)=>{return new Promise((reslove,reject)=>{setTimeout(()=>{console.log(name+1)reject('c1')},1000)})})hook.tapPromise('3',(name,age)=>{return new Promise((reslove,reject)=>{setTimeout(()=>{console.log(name+3)reslove('c3')},3000)})})hook.tapPromise('2',(name,age)=>{return new Promise((reslove,reject)=>{setTimeout(()=>{console.log(name+2)reslove('c2')},2000)})})hook.promise('GMX','18').then((res)=>{console.log('res:'+res);}).catch(e=>{console.log('err'+e)})//"GMX1"//"errc1"
拦截器 interception
所有的hook 都可以添加拦截器 interception
var {SyncHook} = require("tapable")const hook = new SyncHook(["name", "age"]);hook.intercept({call: (source, target, routesList) => {console.log("Starting to calculate routes");},register: (tapInfo) => {// tapInfo = { type: "promise", name: "GoogleMapsPlugin", fn: ... }console.log(`${tapInfo.name} is doing its job`);return tapInfo; // may return a new tapInfo object}})
HookMap
可以通过 hookMap 创建一组hook
const keyedHook = new HookMap(key => new SyncHook(["arg"]))keyedHook.for("some-key").tap("MyPlugin", (arg) => { /* ... */ });keyedHook.for("some-key").tapAsync("MyPlugin", (arg, callback) => { /* ... */ });keyedHook.for("some-key").tapPromise("MyPlugin", (arg) => { /* ... */ });
MultiHook
可以将多个hook 收集起来。
const { MultiHook } = require("tapable");this.hooks.allHooks = new MultiHook([this.hooks.hookA, this.hooks.hookB]);
