tapable是什么?
借用官网的简介: 这个小型库是 webpack 的一个核心工具,但也可用于其他地方, 以提供类似的插件接口。 在 webpack 中的许多对象都扩展自 tapable 类。 它对外暴露了 tap,tapAsync 和 tapPromise 等方法, 插件可以使用这些方法向 webpack 中注入自定义构建的步骤,这些步骤将在构建过程中触发。
简而言之,tapable是支持webpack打包的底层核心库,控制打包在什么阶段调用Plugin的库,其核心功能就是控制一系列注册事件的执行顺序,这东西有点像node里的(eventEmitter)但是比他复杂得多,其控制方式通过tapbale的hook(钩子)实现。
hook的种类
打开我们的node_modules中查找tapable可以看到hook的种类
exports.SyncHook = require("./SyncHook");
exports.SyncBailHook = require("./SyncBailHook");
exports.SyncWaterfallHook = require("./SyncWaterfallHook");
exports.SyncLoopHook = require("./SyncLoopHook");
exports.AsyncParallelHook = require("./AsyncParallelHook");
exports.AsyncParallelBailHook = require("./AsyncParallelBailHook");
exports.AsyncSeriesHook = require("./AsyncSeriesHook");
exports.AsyncSeriesBailHook = require("./AsyncSeriesBailHook");
exports.AsyncSeriesWaterfallHook = require("./AsyncSeriesWaterfallHook");
tapbale按照执行机制可以分为同步和异步两种,异步又可以为(并行和串行两种模式)。
同步钩子
SynckHook
简介:串行同步执行,不关心返回什么,触发后,按着事件注册的先后顺序执行。
- SynckHook是一个类,需要创建实例,传入一个数组参数为触发事件时传入的参数。
- tap用于注册事件,第一个为事件名,第二个为回调函数。
演示代码
// SyncHook 钩子的使用
const { SyncHook } = require("tapable");
// 创建实例
let syncHook = new SyncHook(["name", "age"]);
// 注册事件
syncHook.tap("fn1", (name, age) => console.log("fn1-->", name, age));
syncHook.tap("fn2", (name, age) => console.log("fn2-->", name, age));
syncHook.tap("fn3", (name, age) => console.log("fn3-->", name, age));
// 触发事件,让监听函数执行
syncHook.call("xiaobaba", 18);
//fn1-->xiaobaba 18
//fn2-->xiaobaba 18
//fn3-->xiaobaba 18
SyncBailHook
简介:串行同步执行,某个监听返回undefined时,后续不执行。
演示代码
//fn2 return的不是undefined而是2,fn3不会执行。
// SyncHook 钩子的使用
const { SyncBailHook } = require("tapable");
// 创建实例
let syncHook = new SyncBailHook(["name", "age"]);
// 注册事件
syncBailHook.tap("fn1", (name, age) => console.log("fn1-->", name, age));
syncBailHook.tap("fn2", (name, age) => {
console.log("fn2", name, age);
return "2";//不是undefined
});
syncBailHook.tap("fn3", (name, age) => console.log("fn3-->", name, age));
// 触发事件,让监听函数执行
syncHook.call("xiaobaba", 18);
//fn1-->xiaobaba 18
//fn2-->xiaobaba 18
//fn3不执行熔断
SyncWaterfallHook
简介:串行同步执行,上一个事件处理函数的返回值作为参数传递给下一个事件处理函数行。
演示代码
// SyncHook 钩子的使用
const { SyncWaterfallHook } = require("tapable");
// 创建实例
let syncHook = new SyncWaterfallHook(["name", "age"]);
// 注册事件
syncHook.tap("fn1", (name, age) => {
console.log("fn1", name, age);
return "1";
});
syncHook.tap("fn2", (name, age) => {
console.log("fn2", name, age);
return "2";
});
syncHook.tap("fn3", (name, age) => {
console.log("fn3", name, age);
});
// 触发事件,让监听函数执行
syncHook.call("xiaobaba", 18);
//fn1-->xiaobaba 18
//fn2-->1 18
//fn3-->2 18
SyncLoopHook
简介:串行同步执行,事件处理函数返回 true 表示继续循环。
fn1如果return的值不是undefine儿是true,会循环调用fn1,对num1累加。
演示代码
// SyncLoopHook 钩子的使用
const { SyncLoopHook } = require("tapable");
// 创建实例
let syncLoopHook = new SyncLoopHook(["name", "age"]);
// 定义辅助变量
let num1 = 0;
let num2 = 0;
// 注册事件
syncLoopHook.tap("fn1", (name, age) => {
console.log("fn1", name, age);
return num1++>3 ? undefined:true;
});
syncLoopHook.tap("fn2", (name, age) => {
console.log("fn2", name, age);
return "2";
});
syncLoopHook.tap("fn3", (name, age) => {
console.log("fn3", name, age);
});
// 触发事件,让监听函数执行
syncLoopHook.call("xiaobab", 18);
fn1 xiaobab 18
// fn1 xiaobab 18
// fn1 xiaobab 18
// fn1 xiaobab 18
// fn1 xiaobab 18
// fn2 xiaobab 18
// fn3 xiaobab 18
异步钩子
Async 类型可以使用 tap、tapSync 和 tapPromise 注册不同类型的插件 “钩子”,分别通过 call、callAsync 和 promise 方法调用。
串行
AsyncSeriesHook
简介:使用tapPromise和promise的方式异步串行执行,输出时间为6秒左右。
颜时代吗
const { AsyncSeriesHook } = require("tapable");
// 创建实例
let Hook = new AsyncSeriesHook(["name", "age"]);
// 注册事件
console.time("time");
Hook.tapPromise("fn1", (name, age) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("fn1", name, age, new Date());
resolve("1");
}, 2000);
});
});
Hook.tapPromise("fn2", (name, age, callback) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("fn2", name, age, new Date());
resolve("3");
}, 4000);
});
});
// 触发事件,让监听函数执行
Hook.promise("xiaobaba", 18).then(ret => {
console.log("complete");
console.timeEnd("time");
});
//fn1 xiaobaba 18 2021-03-18T08:14:55.027Z
//fn2 xiaobaba 18 2021-03-18T08:14:59.035Z
//complete
//time: 6018.366ms
AsyncSeriesBailHook
简介:使用tapPromise和promise的方式异步串行熔断方式,某个监听undefined不执行。
const { AsyncSeriesBailHook } = require("tapable");
// 创建实例
let Hook = new AsyncSeriesBailHook(["name", "age"]);
// 注册事件
console.time("time");
Hook.tapPromise("fn1", (name, age) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("fn1", name, age, new Date());
resolve("1");
}, 2000);
});
});
Hook.tapPromise("fn2", (name, age) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("fn2", name, age, new Date());
resolve("3");
}, 4000);
});
});
// 触发事件,让监听函数执行
Hook.promise("xiaobaba", 18).then(ret => {
console.log("complete");
console.timeEnd("time");
});
// fn1 xiaobaba 18 2021-03-18T08:20:45.652Z
// complete
// time: 2009.471ms
AsyncSeriesWaterfallHook
简介:使用tapPromise和promise的方式异步串行瀑布方式,上一个事件处理函数的返回值作为参数传递给下一个事件处理函数行。
resolve("1")传递给下一个fn2,串行时间大约为6秒左右。
const { AsyncSeriesWaterfallHook } = require("tapable");
// 创建实例
let Hook = new AsyncSeriesWaterfallHook(["name", "age"]);
// 注册事件
console.time("time");
Hook.tapPromise("fn1", (name, age) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("fn1", name, age, new Date());
resolve("1");
}, 2000);
});
});
Hook.tapPromise("fn2", (name, age) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("fn2", name, age, new Date());
resolve("3");
}, 4000);
});
});
// 触发事件,让监听函数执行
Hook.promise("xiaobaba", 18).then(ret => {
console.log("complete");
console.timeEnd("time");
});
// fn1 xiaobaba 18 2021-03-18T08:20:45.652Z
// complete
// time: 2009.471ms
// kdsdeMacBook-Pro:TABPABLE kongdesheng$ node ./syncHook.js
// fn1 xiaobaba 18 2021-03-18T08:23:24.013Z
// fn2 1 18 2021-03-18T08:23:28.018Z
// complete
// time: 6010.077ms
// kdsdeMacBook-Pro:TABPABLE kongdesheng$
AsyncParallelHook
简介:异步并行执行,通过 tapAsync 注册的事件,通过 callAsync 触发,通过 tapPromise 注册的 事件,通过 promise 触发。
const { AsyncParallelHook } = require("tapable");
// 创建实例
let Hook = new AsyncParallelHook(["name", "age"]);
// 注册事件
console.time("time");
Hook.tapAsync("fn1", (name, age, callback) => {
setTimeout(() => {
console.log("fn1", name, age, new Date());
callback();
}, 1000);
});
Hook.tapAsync("fn2", (name, age, callback) => {
setTimeout(() => {
console.log("2", name, age, new Date());
callback();
}, 2000);
});
// 触发事件,让监听函数执行
Hook.callAsync("xiaobaba", 18, () => {
console.log("complete");
console.timeEnd("time");
});
// fn1 xiaobaba 18 2021-03-18T07:55:22.298Z
// 2 xiaobaba 18 2021-03-18T07:55:23.298Z
// complete
// time: 2006.765ms
// tapPromise/promise 的使用
const { AsyncParallelHook } = require("tapable");
// 创建实例
let Hook = new AsyncParallelHook(["name", "age"]);
// 注册事件
console.time("time");
Hook.tapPromise("fn1", (name, age) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("fn1", name, age, new Date());
resolve("1");
}, 2000);
});
});
Hook.tapPromise("fn2", (name, age, callback) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("fn2", name, age, new Date());
resolve("3");
}, 4000);
});
});
// 触发事件,让监听函数执行
Hook.promise("xiaobaba", 18).then(ret => {
console.log("complete");
console.timeEnd("time");
});
fn1 xiaobaba 18 2021-03-18T08:01:37.625Z
fn2 xiaobaba 18 2021-03-18T08:01:39.622Z
complete
time: 4005.554ms
AsyncParallelBailHook
简介:并行异步执行,某个监听返回undefined时,后续不执行。
const { AsyncParallelBailHook } = require("tapable");
// 创建实例
let Hook = new AsyncParallelBailHook(["name", "age"]);
// 注册事件
console.time("time");
Hook.tapAsync("fn1", (name, age, callback) => {
setTimeout(() => {
console.log("fn1", name, age, new Date());
callback();
}, 1000);
});
Hook.tapAsync("fn2", (name, age, callback) => {
setTimeout(() => {
console.log("2", name, age, new Date());
callback('error');
}, 2000);
});
// 触发事件,让监听函数执行
Hook.callAsync("xiaobaba", 18, () => {
console.log("complete");
console.timeEnd("time");
});