Tapable是一个轻量级的JavaScript钩子(hook)库,它提供了一种简单而灵活的方式,用于在各种不同的生命周期和场景中注册和触发回调函数,是webpack的核心。
基础钩子(Base Hook) :这是Tapable库中最基本的钩子类型,它只是简单地调用注册的事件回调,并不关心其内部的运行逻辑。
class BaseHook {
constructor() {
this.taps = []; // 存放所有的注册项
}
// 注册回调函数
tap(id, fn) {
this.taps.push( fn );
}
// 执行回调函数
call(context) {
for (let i = 0; i < this.taps.length; i++) {
const fn = this.taps[i];
fn(context);
}
}
}
熔断钩子(Bail Hook) :当一个事件回调运行时返回的值不为undefined时,会停止后面事件回调的执行
class BailHook extends BaseHook {
call(context) {
for (let i = 0; i < this.taps.length; i++) {
const fn = this.taps[i];
const result = fn(context);
if (result !== undefined) {
// 如果返回值不是undefined,则停止后续回调的执行
break;
}
}
}
}
瀑布钩子(Waterfall Hook) :瀑布钩子会在调用一个回调函数时传入前一个回调的返回值,并将其作为下一个回调的第一个参数。
class WaterfallHook extends BaseHook {
constructor() {
super();
}
call(...context) {
let [first,...others] = this.taps
let ret = first(...context)
others.reduce((a,b)=>{
const result = b(a,...context.slice(1))
return result?result : a
},ret ?ret:context[0])
}
}
循环钩子(Loop Hook) :如果当前执行的事件回调的返回值不是undefined,重新从第一个注册的事件回调处执行,直到当前执行的事件回调没有返回值。
class LoopHook extends BaseHook {
constructor() {
super();
this.executing = false; // 用于标记当前是否正在执行回调
}
call(context) {
if (this.executing) {
return; // 如果正在执行回调,则直接返回
}
this.executing = true;
for (let i = 0; i < this.taps.length; i++) {
const fn = this.taps[i];
const result = fn(context);
if (result !== undefined) { // 如果返回值不是undefined,则重新从第一个注册的事件回调处执行
this.executing = false; // 标记当前不正在执行回调
this.call(context); // 重新执行call方法
return; // 执行完毕后直接返回,不继续执行后续的回调函数
}
}
this.executing = false; // 执行完毕后标记当前不正在执行回调
}
}