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]);