2025年tapable详解

tapable详解tapable 详解 tapable 是 webpack 内部使用的一个流程管理工具 主要用来串联插件 完善事件流执行 1 安装 tapable yarn add tapable 2 常用 hooks import SyncHook SyncBailHook SyncWaterfal SyncLoopHook

大家好,我是讯享网,很高兴认识大家。

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

讯享网 
小讯
上一篇 2025-03-12 23:46
下一篇 2025-03-31 14:46

相关推荐

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