tapable

113 阅读2分钟

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; // 执行完毕后标记当前不正在执行回调  
  }  
}