基于本文回答

播面 播面

文解图解播客视频,多维讲透八股文
0
评论

Tapable 提供了哪些常见的钩子(Hook)类型?(如 SyncHook、AsyncSeriesHook 等)

Tapable 是 Webpack 的核心库,它为 Webpack 提供了强大的插件架构(基于发布-订阅模式)。Webpack 中几乎所有的核心对象(如 CompilerCompilation)都继承或使用了 Tapable 的 Hook。

Tapable 提供了 9 种 常见的钩子(Hook)类型。为了方便理解,这些钩子可以根据 执行机制(同步/异步、串行/并行)控制流逻辑(Bail、Waterfall、Loop) 进行分类。


一、 核心概念理解(命名规律)

Tapable 钩子的名称是组合而来的,理解以下关键字就能轻松掌握所有钩子:

  1. 执行时机 / 模式

    • Sync(同步):按顺序同步执行,注册的函数必须是同步函数。
    • AsyncSeries(异步串行):按顺序异步执行,前一个异步任务完成后,才会执行下一个。
    • AsyncParallel(异步并行):所有异步任务同时(并行)发起执行。
  2. 控制流逻辑(后缀)

    • 基本类型(Basic):无特殊后缀。依次执行每个插件,忽略插件的返回值。
    • Bail(保险/熔断):当某个插件返回 undefined 的值时,立即中断后续插件的执行。
    • Waterfall(瀑布/流水线):前一个插件的返回值会作为下一个插件的入参依次传递下去。
    • Loop(循环):如果某个插件返回 undefined 的值,则重新从第一个插件开始循环执行,直到所有插件都返回 undefined

二、 9 种常见钩子详解

1. 同步钩子(Sync Hooks)

只能使用 tap 注册,call 触发。

  • SyncHook
    • 特点:最基础的同步钩子,按顺序执行,忽略返回值。
    • 场景:纯通知类事件,如 Webpack 编译开始。
  • SyncBailHook
    • 特点:同步熔断钩子。一旦有插件返回非 undefined,立即停止执行后续插件。
    • 场景:寻找符合条件的插件,一旦找到就终止。
  • SyncWaterfallHook
    • 特点:同步瀑布钩子。上一个插件的返回值是下一个插件的第一个参数。
    • 场景:代码或配置的逐层修改/加工(如 Loader 链式处理)。
  • SyncLoopHook
    • 特点:同步循环钩子。只要有插件返回非 undefined,就从头重新执行所有插件。

2. 异步串行钩子(Async Series Hooks)

可使用 taptapAsync(回调)、tapPromise(Promise)注册,用 callAsyncpromise 触发。按顺序依次执行。

  • AsyncSeriesHook
    • 特点:异步串行基本钩子。一个异步任务完成后,才执行下一个。
    • 场景:有先后顺序依赖的异步操作,如构建资源打包文件。
  • AsyncSeriesBailHook
    • 特点:异步串行熔断钩子。某个异步任务返回非 undefined(或 promise resolve 非 undefined),阻断后续任务。
  • AsyncSeriesWaterfallHook
    • 特点:异步串行瀑布钩子。异步流式传递数据,上一个异步结果传给下一个。
    • 场景:异步获取数据并逐层加工处理。
  • AsyncSeriesLoopHook
    • 特点:异步串行循环钩子。如果异步任务返回非 undefined,重新开始循环。

3. 异步并行钩子(Async Parallel Hooks)

同样支持 tapAsync / tapPromise。所有注册的异步任务同时触发。

  • AsyncParallelHook
    • 特点:异步并行基本钩子。类似于 Promise.all,所有异步任务同时发起,等全部完成后再继续。
    • 场景:互不干扰的异步操作,如多进程编译、同时分析多个无依赖的资源。
  • AsyncParallelBailHook
    • 特点:异步并行熔断钩子。虽然是并行执行,但只要有一个任务返回了有效值,就会提前触发最终的回调(相当于 Promise.race 的某种变体)。

三、 一张图总结 Tapable 钩子矩阵

逻辑类型 \ 执行模式 Sync (同步) AsyncSeries (异步串行) AsyncParallel (异步并行)
Basic (基本) SyncHook AsyncSeriesHook AsyncParallelHook
Bail (熔断) SyncBailHook AsyncSeriesBailHook AsyncParallelBailHook
Waterfall (瀑布) SyncWaterfallHook AsyncSeriesWaterfallHook (并行无法实现数据流传递)
Loop (循环) SyncLoopHook AsyncSeriesLoopHook (并行循环无实际逻辑意义)

四、 补充:注册与触发方式

使用 Tapable 时,插件的监听(订阅)与触发(发布)方式如下:

Hook 类型 注册方式 (Subscribe) 触发方式 (Publish)
Sync tap call(...)
Async tap (同步模拟)
tapAsync (cb 回调)
tapPromise (返回 Promise)
callAsync(..., done)
promise(...)

简单代码示例(以 AsyncSeriesHook 为例):

javascript
const { AsyncSeriesHook } = require('tapable');

// 1. 实例化 hook,指定接收的参数
const hook = new AsyncSeriesHook(['name']);

// 2. 注册插件 (Promise 方式)
hook.tapPromise('PluginA', (name) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log(`PluginA: ${name}`);
      resolve();
    }, 1000);
  });
});

// 3. 触发 hook
hook.promise('Webpack').then(() => {
  console.log('所有异步串行任务完成!');
});