Tapable 的使用
Tapable 本身不能使用,只能使用从它导出的 Hook
const {
SyncHook,
SyncBailHook,
SyncWaterfallHook,
SyncLoopHook,
AsyncSeriesHook,
AsyncSeriesBailHook,
AsyncSeriesWaterfallHook,
AsyncParallelHook,
AsyncParallelBailHook,
} = require('tapable');
Hook 可以按照两种标准来分类
- 事件回调的运行逻辑:
- Basic:基本类型,按顺序执行注册的回调
- Bail:保险类型,当一个事件回调的返回值不为 undefined 时,停止后面的回调执行
- Waterfall:瀑布类型,如果当前事件回调的返回值不为 undefined,那么返回值就作为下一个回调的第一个参数
- Loop:循环类型,如果当前事件回调的返回值不为 undefined,回到第一个事件注册的回调执行,直到所有的回调都返回 undefined(没有返回)
- 触发事件的方式:
- Sync:以 sync 开头的 hook,同步的执行注册的事件;只能使用 tap 方法注册,使用 tapAsync 或 tapPromise 注册会报错
- AsyncSerise:以 asyncSerise 开头的 hook,按顺序的执行事件回调,如果回调是异步的,等异步执行完成才会执行下一个事件回调;可以使用 tap、tapAsync、tapPromise 注册事件回调;不能使用 call() 方法触发回调
- AsyncParalle:以 asyncParalle 开头的 hook,并行的执行所有的事件回调
Sync hook
// 实例化 Hook
const { SyncHook } = require('tapable');
// 实例化钩子类时传入的数组,实际上只用上了数组的长度,名称是为了便于维护
const hook = new SyncHook(['name']);
// 事件注册
hook.tap('first', (name) => {
console.log('first ', name);
});
// 第一个参数可以是事件回调的名字,也可以是配置对象
hook.tap({name: 'second'}, (name) => {
console.log('second ', name);
});
//触发
hook.call('jack'); // 对应 sync hook
/**
* Console output:
*
* first jack
* second jack
*/
AsyncSerise hook
const { AsyncSeriesHook } = require('tapable');
const hook = new AsyncSeriesHook(['name']);
// 事件回调接收到 callback
hook.tapAsync('first', (name, callback) => {
console.log('first', name, callback);
callback();
});
// 最后一个传入参数是回调函数
hook.callAsync('callAsync', (error) => {
console.log('callAsync', error);
});
/**
* Console output:
*
* first callAsync [Function]
* callAsync undefined
*/
callAsync 的第二个参数:错误回调callback
- 事件回调中必须调用 callback,才能执行下一个事件回调
- 调用 callback 时不传入参数时执行下一个回调,传入第一个参数代表有错误发生,接下来会执行触发时的回调
Async hook 使用 tapPromise 注册
const { AsyncSeriesHook } = require('tapable');
const hook = new AsyncSeriesHook(['name']);
hook.tapPromise('first', (name) => {
console.log('first', name);
return Promise.resolve('first');
});
hook.tapPromise('second', (name) => {
console.log('second', name);
return Promise.resolve('second');
});
const promise = hook.promise('promise');
console.log(promise);
promise.then(value => {
// value 是 undefined,不会接收到事件回调中传入的值
console.log('value', value);
}, reason => {
// 事件回调返回的 Promise 对象状态是 Rejected
// reason 会有事件回调中传入的错误信息
console.log('reason', reason);
});
/**
* Console output:
*
* first promise
* Promise { <pending> } // 同步代码
* second promise // tapPromise 是微任务,所以会在同步代码后执行
* value undefined
*/
promise 执行之后会返回一个 Promise 对象。在使用 tapPromise 注册事件回调时,事件回调必须返回一个 Promise 对象,否则会报错,这是为了确保事件回调能够按照顺序执行。
拦截器
我们可以给钩子类添加拦截器,这样就能对事件回调的注册、调用以及事件的触发进行监听
const { SyncHook } = require('tapable');
const hook = new SyncHook();
hook.intercept({
// 注册时执行
register(tap) {
console.log('register', tap);
return tap;
},
// 触发事件时执行
call(...args) {
console.log('call', args);
},
// 在 call 拦截器之后执行
loop(...args) {
console.log('loop', args);
},
// 事件回调调用前执行
tap(tap) {
console.log('tap', tap);
},
});