tapable详解
tapable是webpack内部使用的一个流程管理工具,主要用来串联插件,完善事件流执行。
1.安装tapable
yarn add tapable
讯享网
2. 常用hooks
讯享网import { SyncHook, SyncBailHook, SyncWaterfallHook, SyncLoopHook, AsyncParallelHook, AsyncParallelBailHook, AsyncSeriesHook, AsyncSeriesBailHook, AsyncSeriesWaterfallHook } form 'tapable';
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gBgy8rW0-04)(D:\download\tapable.png)]
tapable通过
tap注册一个事件,通过call执行该钩子注册的所有事件。tapable的每个hooks都
tap一个或多个事件。
tapAsync/callAsync、tapPromise/Promise用于注册同步执行的异步事件,callAsync用在并行执行的异步钩子完成后再执行该函数。
用法示例:
new SyncHook([arg1,arg2,...])
hooks接收一个数组参数,参数为执行回调事件所需的参数名。
- call:
(...args) => void当你的钩子触发之前,(就是call()之前),就会触发这个函数,你可以访问钩子的参数.多个钩子执行一次 - tap:
(tap: Tap) => void每个钩子执行之前(多个钩子执行多个),就会触发这个函数 - loop:
(...args) => void这个会为你的每一个循环钩子(LoopHook, 就是类型到Loop的)触发,具体什么时候没说 - register:
(tap: Tap) => Tap | undefined每添加一个Tap都会触发 你interceptor上的register,你下一个拦截器的register 函数得到的参数 取决于你上一个register返回的值,所以你最好返回一个 tap 钩子.
2.1 SyncHook
同步串行,在触发事件之后,会依次执行注册的所有事件处理函数。其原理是将监听(订阅)的函数存放到一个数组中, 发布时遍历数组中的监听函数并且将发布时的 arguments传递给监听函数。
不关心返回值,从上到下依次执行注册事件。
讯享网 const hook = new SyncHook(['name', 'sex']) /* tap(options,function): options是事件描述,可以为一个字符串,也可以为一个对象,为对象时必须包含name属性,描述该插件名称。 function:回调函数 */ // 打印我的名字 hook.tap('printName', (name) => { console.log('my name is ' + name); }) hook.tap('printSex', (name, sex) => { console.log('I’m a ' + sex); }) // call(arg1,arg2,...) hook.call('张三', 'man');
执行结果:
my name is 张三
I’m a man
Basic Hook:依次执行注册事件,无法中断。
2.2 SyncBailHook
同步串行,当注册事件无返回值,或者返回undefined时继续执行之后的注册事件,否则中断执行。
const hook = new SyncBailHook(['name', 'sex', 'age']) /* tap(options,function): options是事件描述,可以为一个字符串,也可以为一个对象,为对象时必须包含name属性,描述该插件名称。 function:回调函数 */ // 打印我的名字 hook.tap('printName', (name) => { const nameStr = 'my name is ' + name; console.log(nameStr); return; }) hook.tap('printSex', (name, sex) => { const sexStr = 'I’m a ' + sex; console.log(sexStr); return sexStr; }) hook.tap('printAge', (name, sex, age) => { const ageStr = 'I’m ' + age + ' years old'; console.log(ageStr); }) // call(arg1,arg2,...) hook.call('张三', 'man', 29);
执行结果:
my name is 张三
I’m a man
Bail Hook:运行提前退出执行函数,当存在返回值不为undefined时,则不再进行之后的事件执行。
2.3 SyncWaterfallHook
同步瀑布流,依次执行注册的所有事件,并将上一个事件的执行结果作为下一个事件的入参。
讯享网 const hook = new SyncWaterfallHook(['name', 'sex', 'age']) /* tap(options,function): options是事件描述,可以为一个字符串,也可以为一个对象,为对象时必须包含name属性,描述该插件名称。 function:回调函数 */ // 打印我的名字 hook.tap('printName', (name, sex, age) => { const nameStr = 'my name is ' + name; console.log(nameStr); return { sex, age }; }) hook.tap('printSex', (data) => { const sexStr = 'I’m a ' + data.sex; console.log(sexStr); return data.age; }) hook.tap('printAge', (age) => { const ageStr = 'I’m ' + age + ' years old'; console.log(ageStr); }) // call(arg1,arg2,...) hook.call('张三', 'man', 29);
执行结果:
my name is 张三
I’m a man
I’m 29 years old
Waterfall Hook:接收上一个注册事件的返回值作为下一个注册事件的参数。
2.4 SyncLoopHook
同步循环执行,当注册事件返回值非undefined时,循环执行该注册事件,直至返回undefined时,才继续执行下一个事件。
const hook = new SyncLoopHook(['name', 'sex', 'age']) /* tap(options,function): options是事件描述,可以为一个字符串,也可以为一个对象,为对象时必须包含name属性,描述该插件名称。 function:回调函数 */ // 打印我的名字 let num = 0; hook.tap('printName', (name) => { const nameStr = 'my name is ' + name; console.log(nameStr); num++; return num === 3 ? undefined : false; }) hook.tap('printSex', (name, sex) => { const sexStr = 'I’m a ' + sex; console.log(sexStr); return; }) hook.tap('printAge', (name, sex, age) => { const ageStr = 'I’m ' + age + ' years old'; console.log(ageStr); }) // call(arg1,arg2,...) hook.call('张三', 'man', 29);
执行结果:
my name is 张三
my name is 张三
my name is 张三
I’m a man
I’m 29 years old
Loop Hook:循环执行注册事件,直至返回undefined才进入下一个注册事件。
2.5 AsyncParallelHook
异步并行执行,当所有注册事件都执行完成后,才执行callAsync或者promise。
讯享网const hook = new AsyncParallelHook(['name', 'sex', 'age']) /* tap(options,function): options是事件描述,可以为一个字符串,也可以为一个对象,为对象时必须包含name属性,描述该插件名称。 function:回调函数 */ // 打印我的名字 let num = 0; console.time('time') hook.tapAsync('printName', (name, sex, age, next) => { setTimeout(() => { const nameStr = 'my name is ' + name; console.log(nameStr); next(); }, 1000) }) hook.tapAsync('printSex', (name, sex, age, next) => { setTimeout(() => { const sexStr = 'I’m a ' + sex; console.log(sexStr); next(); }, 2000) }) hook.tapAsync('printAge', (name, sex, age, next) => { setTimeout(() => { const ageStr = 'I’m ' + age + ' years old'; console.log(ageStr); next(); }, 3000) }) // call(arg1,arg2,...) hook.callAsync('张三', 'man', 29,()=>{ console.log('执行完成!'); console.timeEnd('time'); });
执行结果:
my name is 张三
I’m a man
I’m 29 years old
执行完成!
time: 3002.5 ms
callAsync:最后一个参数接收一个回调函数,当所有的注册事件都执行完成后,才会执行该回调。
tapAsync:除了hook声明的参数,它还接收一个next()回调,当存在next时,当所有注册事件执行完成后则执行next回调。
Parallel Hook:异步并行执行,所有的异步事件都执行完成后,才执行callAsync/promise定义的回调。
2.6 AsyncSeriesHook
异步串行执行,与AsyncParallelHook类似,所有注册事件执行完成后才会执行callAsync/promise定义的回调。
const hook = new AsyncSeriesHook(['name', 'sex', 'age']) /* tap(options,function): options是事件描述,可以为一个字符串,也可以为一个对象,为对象时必须包含name属性,描述该插件名称。 function:回调函数 */ // 打印我的名字 let num = 0; console.time('time') hook.tapPromise('printName', (name, sex, age) => { return new Promise((resolve, reject) => { setTimeout(() => { const nameStr = 'my name is ' + name; console.log(nameStr); resolve('printName'); }, 1000) }) }) hook.tapPromise('printSex', (name, sex, age) => { return new Promise((resolve, reject) => { setTimeout(() => { const sexStr = 'I’m a ' + sex; console.log(sexStr); resolve('printSex') }, 2000) }) }) hook.tapPromise('printAge', (name, sex, age) => { return new Promise((resolve, reject) => { setTimeout(() => { const ageStr = 'I’m ' + age + ' years old'; console.log(ageStr); resolve('printAge') }, 3000) }) }) // call(arg1,arg2,...) hook.promise('张三', 'man', 29).then(res => { console.log(res); console.timeEnd('time'); });
执行结果:
my name is 张三
I’m a man
I’m 29 years old
undefined
time: 6005.5 ms
2.7 其他
- AsyncParallelBailHook:异步并行且运行中断。
- AsyncSeriesBailHook :异步串行且运行中断。
- AsyncSeriesWaterfallHook:异步串行瀑布流,上一个事件的结果作为下一个事件的参数。
3.拦截器(interception)
所有的钩子函数都有额外的拦截器。
- call:执行
call/callAsync/promise时触发。 - register:定义
tap/tapAsync/tapPromise时触发。 - tap:执行
tap/tapAsync/tapPromise定义的内容时触发。 - loop:执行
SyncLoopHook注册的事件时触发。 - error: 执行报错时触发。
- result: 存在返回结果时触发,主要针对
Waterfall Hook/Bail Hook,在call之前,tap之后触发。 - done: 执行
call/callAsync/promise完成后触发。
讯享网 const hook = new AsyncSeriesHook(['name', 'sex', 'age']) hook.intercept({ call: (name, sex, age) => { console.log('执行拦截器'); }, register: (name) => { console.log('定义钩子函数时的拦截器'); }, tap: () => { console.log('执行钩子函数时的拦截器'); }, loop:()=>{ console.log('循环事件函数执行时的拦截器'); } }) // 打印我的名字 let num = 0; console.time('time') hook.tapPromise('printName', (name, sex, age) => { return new Promise((resolve, reject) => { setTimeout(() => { const nameStr = 'my name is ' + name; console.log(nameStr); resolve('printName'); }, 1000) }) }) hook.tapPromise('printSex', (name, sex, age) => { return new Promise((resolve, reject) => { setTimeout(() => { const sexStr = 'I’m a ' + sex; console.log(sexStr); resolve('printSex') }, 2000) }) }) hook.tapPromise('printAge', (name, sex, age) => { return new Promise((resolve, reject) => { setTimeout(() => { const ageStr = 'I’m ' + age + ' years old'; console.log(ageStr); resolve('printAge') }, 3000) }) }) // call(arg1,arg2,...) hook.promise('张三', 'man', 29).then(res => { console.log(res); console.timeEnd('time'); });
执行结果:
定义钩子函数时的拦截器
定义钩子函数时的拦截器
定义钩子函数时的拦截器
执行拦截器
执行钩子函数时的拦截器
my name is 张三
执行钩子函数时的拦截器
I’m a man
执行钩子函数时的拦截器
I’m 29 years old
undefined
time: 6005. ms
4.HookMap
一个 HookMap是一个Hooks映射的帮助类。实际就是一个hook的key-value数组。
const hookMap = new HookMap(key => new AsyncSeriesWaterfallHook(['name', 'sex', 'age'])); hookMap.tapPromise('myPlugin', 'printName', (name, sex, age) => { return new Promise((resolve, reject) => { setTimeout(() => { const nameStr = 'my name is ' + name; console.log(nameStr); resolve('printName'); }, 1000) }) }); const hook = hookMap.get('myPlugin'); // call(arg1,arg2,...) hook.promise('张三', 'man', 29).then(res => { console.log(res); });
5.MultiHook
把其他的Hook 重定向(转化)成为一个 MultiHook
讯享网import { MultiHook } from "tapable"; const hookA = new SyncHook(['name']); const hookB = new SyncBailHook(['age']); const allHooks = new MultiHook([hookA, hookB]);
.log(nameStr);
resolve(‘printName’);
}, 1000)
})
});
const hook = hookMap.get(‘myPlugin’);
// call(arg1,arg2,…)
hook.promise(‘张三’, ‘man’, 29).then(res => {
console.log(res);
});
5.MultiHook 把其他的Hook 重定向(转化)成为一个 MultiHook
import { MultiHook } from “tapable”;
const hookA = new SyncHook([‘name’]);
const hookB = new SyncBailHook([‘age’]);
const allHooks = new MultiHook([hookA, hookB]);
讯享网

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/54528.html