简介
在看L7源码时,看到我们使用了webpack的核心模块tapable,这个模块是连接webpack各个plugin的关键纽带,简单的说,如果不了解tapable,那肯定看不懂webpack的源码,对于各个plugin的调用机制也不会清楚。
总览
tapable我们可以简单的把它理解成webpack中的EventEmitter,用来发布和订阅消息。它暴露了很多hook,这些hook都是为自定义的plugin挂载提供的: ### 基础用法 可以知道tapable分为同步和异步两种hook,要注意的是异步hook分为并行和串行,而同步hook自然都是串行的。 先了解一下注册和触发的方法:
同步Hook | 异步Hook | 注册 | tap | tapAsync,tapPromise,tap | 触发 | call | callAsync,promise |
---|
最好在Class的构造函数中使用new初始化Hook:接受一个数组参数,触发方法会根据传参,接受同样数量的参数。
class Kunkun{
constructor() {
this.hooks = {
sing: new SyncHook(["song"]),
dance: new SyncWaterfallHook(['danceName']),
rap: new SyncBailHook(),
basketball: AsyncSeriesHook(["shot"]),
};
}
}
const kunkun = new Kunkun();
// 注册方法
// 有参数
kunkun.hooks.sing.tap("GoSing", song => {console.log(`唱了一首${song}`)});
// 无参数
kunkun.hooks.dance.tap("GoDance", danceName => {console.log(`跳了一支${danceName}`)});
kunkun.hooks.rap.tap("GoRap", () => {console.log('来了一首Rap')});
// 注册异步函数
kunkun.hooks.basketball.tapPromise("GoBasketball", (shot, callback) => {
return new Promise(resolve => {
setTimeout(() => {
resolve(`投了一个${shot}分球`);
},1000)
})
});
//执行同步Hook
kunkun.hooks.sing.call('鸡你太美');
kunkun.hooks.dance.call('华尔兹');
kunkun.hooks.rap.call();
//执行异步Hook
myCar.hooks.basketball.promise(2).then((res) => {
console.log(res)
})
Hook详细场景
SyncHook
在触发事件之后,会按照事件注册的先后顺序执行所有的事件处理函数。
SyncBailHook
如果事件处理函数执行时有一个返回值不为空,则跳过剩下未执行的事件处理函数,还依照上述例子:
kunkun.hooks.rap.tap("GoRap1", () => {console.log('来了一首Rap1')});
kunkun.hooks.rap.tap("GoRap2", () => {
console.log('来了一首Rap2');
return 0;
});
kunkun.hooks.rap.tap("GoRap3", () => {console.log('来了一首Rap3')});
kunkun.hooks.rap.call();
// 来了一首Rap1
// 来了一首Rap2
SyncWaterfallHook
上一个事件处理函数的返回值作为参数传递给下一个事件处理函数,只有第一个绑定的函数里的参数是触发时的实际参数,其他绑定方法里的参数都是上一个的结果:
kunkun.hooks.dance.tap("Dance1", danceName => {
return `跳了一支${danceName}1`
});
kunkun.hooks.dance.tap("Dance2", (data) => {
return `跳了一支${danceName}2`
});
kunkun.hooks.dance.tap("Dance3", (data) => {
return `跳了一支${danceName}3`
});
kunkun.hooks.dance.call('华尔兹');
//跳了一支华尔兹123
SyncLoopHook
事件处理函数返回 true表示循环执行当前事件处理函数,返回 undefined表示结束循环, 和SyncBailHook不同,SyncBailHook 只决定是否继续向下执行后面的事件处理函数,而 SyncLoopHook 的循环是指循环执行每一个事件处理函数,直到返回 undefined 为止,才会继续向下执行其他事件处理函数,执行机制同理。
let syncLoopHook = new SyncLoopHook(["name", "age"]);
let temp = 0;
// 注册事件
syncLoopHook.tap("1", name => {
console.log("1", name, temp);
return temp++ < 2 ? true : undefined;
});
syncLoopHook.tap("2", name => {
console.log("2", name, temp);
return temp++ < 5 ? true : undefined;
});
syncLoopHook.tap("3", name => console.log("3", name));
syncLoopHook.call("maosong");
// 1 maosong 0
// 1 maosong 1
// 1 maosong 2
// 2 maosong 3
// 2 maosong 4
// 2 maosong 5
// 3 maosong
AsyncParallelHook
所有注册的方法同步并行,和Promise.all()一样
AsyncSeriesHook
所有注册的方法串行,也就是一个方法执行完,有了结果之后再执行下一个
AsyncParallelBailHook
和SyncBailHook一个思想,只不过加入了异步
AsyncSeriesBailHook
和SyncBailHook一个思想,只不过加入了异步
AsyncSeriesWaterfallHook
AsyncSeriesHook + SyncWaterfallHook 详情去查看这俩Hook
异步注册和触发两种方式的区别
tapAsync / callAsync
在AsyncParallelHook中,注册时提供done()方法来表明异步结束,触发时可以传入callback来在所有注册的方法都运行结束后触发回调
const { AsyncParallelHook } = require("tapable");
let asyncParallelHook = new AsyncParallelHook(["name"]);
asyncParallelHook.tapAsync("1", (name, done) => {
settimeout(() => {
console.log("1", name);
done();
}, 1000);
});
asyncParallelHook.tapAsync("2", (name, done) => {
settimeout(() => {
console.log("2", name);
done();
}, 1000);
});
// 触发事件,让监听函数执行
asyncParallelHook.callAsync("maosong", () => {
console.log("over");
});
// 1 maosong
// 2 maosong
// over
在AsyncSeriesHook中提供next()方法来进入下一个注册的监控方法,用法和上面一样。
done()和next()的区别?
tapPromise /promise
具体示例看一开始的kunkun示例就好,需要返回一个promise实例
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!