由浅入深学习Tapable
文章目录
- 由浅入深学习Tapable
- Tapable是什么
- Tapable的Hook分类
- 同步和异步的
- 使用
- Sync*同步类型钩子
- 基本使用
- bail
- Loop
- Waterfall
- Async*异步类型钩子
- Parallel
- Series
由浅入深学习Tapable
webpack有两个非常重要的类:Compiler和Compilation。他们通过注入插件的方式,来监听webpack的所有生命周期,插件的注入离不开各种各样的Hook,而他们的Hook是如何得到的呢?其实是创建了Tapable库中各种Hook的实例。
Tapable是什么
Tapable是一个任务调度库,它的核心思基于发布订阅模式是将任务执行逻辑和调度逻辑分离,Tapable在webpack中用于plugin的管理,在可以实现复杂调度逻辑的同时尽可能保证可维护性。
Tapable的机制与Event类似,它可以用来定义各种各样的钩子,相当于Event中的事件注册,但是与Event不同的是,Event中各个事件之间相互不关联,互不影响,但是tapable注册的事件之间可以是有关系的,这种关系通过Tapable定义的各个钩子类来实现。其实,Tapable的核心就是这些钩子类。因此,我们接下来的重点就是讲述这些钩子类,并实现它们。
Tapable的Hook分类
同步和异步的
- 以sync开头的,是同步的Hook
- 以async开头的,两个事件处理回调,不会等待上一次处理回调结束后再执行下一次回调

使用
Tapable的每个子类都是一个用于注册和触发事件的钩子,我们可以查看一下SyncHook实例身上有哪些属性,找到它注册事件和触发事件的属性。
SyncHook {_args: [],name: undefined,taps: [],interceptors: [],_call: [Function: CALL_DELEGATE],call: [Function: CALL_DELEGATE], // 用于触发同步事件的钩子_callAsync: [Function: CALL_ASYNC_DELEGATE],callAsync: [Function: CALL_ASYNC_DELEGATE], // 用于触发异步事件的钩子_promise: [Function: PROMISE_DELEGATE],promise: [Function: PROMISE_DELEGATE],_x: undefined,compile: [Function: COMPILE],tap: [Function: tap], // 用于注册同步事件的钩子tapAsync: [Function: TAP_ASYNC], // 用于注册异步事件的钩子tapPromise: [Function: TAP_PROMISE],constructor: [Function: SyncHook]
}
Sync*同步类型钩子
基本使用
const { SyncHook } = require("tapable");class myCompiler {constructor() {this.hooks = {// 1. 创建hooks(webpack完成)syncHook: new SyncHook(["name", "age"]),};// 2. 用hooks监听事件(自定义plugin)this.hooks.syncHook.tap("event1", (name, age) => {console.log("event1事件监听执行了:", name, age);});this.hooks.syncHook.tap("event2", (name, age) => {console.log("event2事件监听执行了:", name, age);});}
}const compiler = new myCompiler();
// 3. 发出去事件(webpack完成)
compiler.hooks.syncHook.call("小张", 20);
结果:

bail
当有返回值时,就不会执行后续的事件触发了
const { SyncBailHook } = require("tapable");class myCompiler {constructor() {this.hooks = {// 1. 创建hooksbailHook: new SyncBailHook(["name", "age"]),};// 2. 用hooks监听事件(自定义plugin)this.hooks.bailHook.tap("event1", (name, age) => {console.log("event1事件监听执行了:", name, age);return 123});this.hooks.bailHook.tap("event2", (name, age) => {console.log("event2事件监听执行了:", name, age);});}
}const compiler = new myCompiler();
// 3. 发出去事件
compiler.hooks.bailHook.call("小张", 20);
输出结果:

Loop
当返回值为true,就会反复执行该事件,当返回值为undefined或者不返回内容,就退出事件
const { SyncLoopHook } = require("tapable");class myCompiler {constructor() {this.hooks = {// 1. 创建hooksloopHook: new SyncLoopHook(["name", "age"]),};let count = 0;// 2. 用hooks监听事件(自定义plugin)this.hooks.loopHook.tap("event1", (name, age) => {if (count < 5) {console.log("event1事件监听执行了:", name, age);count++;return true;} else {return;}});this.hooks.loopHook.tap("event2", (name, age) => {console.log("event2事件监听执行了:", name, age);});}
}const compiler = new myCompiler();
// 3. 发出去事件
compiler.hooks.loopHook.call("小张", 20);
输出结果:

Waterfall
当返回值不为undefined时,会将这次返回的结果作为下次事件的第一个参数
const { SyncWaterfallHook } = require("tapable");class myCompiler {constructor() {this.hooks = {// 1. 创建hookswaterfallHook: new SyncWaterfallHook(["name", "age"]),};// 2. 用hooks监听事件(自定义plugin)this.hooks.waterfallHook.tap("event1", (name, age) => {console.log("event1事件监听执行了:", name, age);// return “小李”,小李作为下一个事件的第一个参数return "小李";});this.hooks.waterfallHook.tap("event2", (name, age) => {console.log("event2事件监听执行了:", name, age);});}
}const compiler = new myCompiler();
// 3. 发出去事件
compiler.hooks.waterfallHook.call("小张", 20);
输出结果:

Async*异步类型钩子
Parallel
并行,不会等到上一个事件回调执行结束,才会执行下一次事件处理回调
const { AsyncParallelHook } = require("tapable");class myCompiler {constructor() {this.hooks = {// 1. 创建hooksparallelHook: new AsyncParallelHook(["name", "age"]),};// 2. 用hooks监听事件(自定义plugin)this.hooks.parallelHook.tapAsync("event1", (name, age) => {setTimeout(() => {console.log("event1事件监听执行了:", name, age);}, 3000);});this.hooks.parallelHook.tapAsync("event2", (name, age) => {setTimeout(() => {console.log("event2事件监听执行了:", name, age);}, 3000);});}
}const compiler = new myCompiler();
// 3. 发出去事件
compiler.hooks.parallelHook.callAsync("小张", 20);
输出结果:

Series
串行,会等待上一次异步的Hook,即按照注册的顺序依次执行
const { AsyncSeriesHook } = require("tapable");class myCompiler {constructor() {this.hooks = {// 1. 创建hooksseriesHook: new AsyncSeriesHook(["name", "age"]),};// 2. 用hooks监听事件(自定义plugin)this.hooks.seriesHook.tapAsync("event1", (name, age, callback) => {console.log("event1事件监听执行了:", name, age);// 这个callback决定下一个事件的执行callback();});this.hooks.seriesHook.tapAsync("event2", (name, age, callback) => {console.log("event2事件监听执行了:", name, age);// 这个callback决定发出事件中的函数执行callback();});}
}const compiler = new myCompiler();
// 3. 发出去事件
// 第三个参数决定第一个事件的执行
compiler.hooks.seriesHook.callAsync("小张", 20, () => {console.log("所有事件都执行完成啦!");
});
输出结果:


相关文章:
由浅入深学习Tapable
文章目录 由浅入深学习TapableTapable是什么Tapable的Hook分类同步和异步的 使用Sync*同步类型钩子基本使用bailLoopWaterfall Async*异步类型钩子ParallelSeries 由浅入深学习Tapable webpack有两个非常重要的类:Compiler和Compilation。他们通过注入插件的方式&a…...
YOLOv5白皮书-第Y6周:模型改进
📌本周任务:模型改进📌 注:对yolov5l.yaml文件中的backbone模块和head模块进行改进。 任务结构图: YOLOv5s网络结构图: 原始模型代码: # YOLOv5 v6.0 backbone backbone:# [from, number, module, args]…...
word之插入尾注+快速回到刚才编辑的地方
1-插入尾注 在编辑文档时,经常需要对一段话插入一段描述或者附件链接等,使用脚注经常因占用篇幅较大导致文档页面内容杂乱,这事可以使用快捷键 ControlaltD 即可在 整个行文的末尾插入尾注,这样文章整体干净整洁,需…...
Qt扫盲-QTableView理论总结
QTableView理论总结 一、概述二、导航三、视觉外观四、坐标系统五、示例代码1. 性别代理2. 学生信息模型3. 对应视图 一、概述 QTableView实现了一个tableview 来显示model 中的元素。这个类用于提供之前由QTable类提供的标准表,但这个是使用Qt的model/view架构提供…...
从外部访问K8s中Pod的五种方式
hostNetwork、 hostPort、 NodePort、 LoadBalancer、 Ingress 暴露Pod与Service一样,因为Pod就是Service的backend 1、hostNetwork:true 这是一种直接定义 Pod 网络的方式。 如果在 Pod 中使用 hostNetwork:true 配置, pod 中运行的应用程序…...
什么是A股交易接口_(股票交易c接口)开发原理
A股交易接口是指用于与国内的证券交易所(上海证券交易所和深圳证券交易所)进行股票买卖交易的电子接口或软件系统。A股交易接口是金融机构、券商以及个人投资者的必备掌握操作技能之一,它提供了实时的股票行情、交易下单、撤单、查询账户信息…...
STM32F4X NVIC中断概念
STM32F4X NVIC中断概念 CPU查询状态两种方式轮询查询中断查询 STM32有关中断的概念中断向量表系统中断外设中断中断号中断优先级 STM32F4X NVIC控制器NVIC控制器简介NVIC寄存器优先级分组 STM32F4X中断配置优先级分组设置配置外设中断 CPU查询状态两种方式 在讲解中断的概念之…...
关于consul的下载方法
linux下 sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo sudo yum -y install consulwindow下 https://developer.hashicorp.com/consul/downloads 然后把里面的exe文件放在gopath下就行了 验证…...
应用在汽车前照灯系统中的环境光传感芯片
为了保证行车照明的安全性和方便性,减轻驾驶员的劳动强度。近年来,出现了许多新的照明控制系统,例如用于日间驾驶的自动照明系统、光束调节系统、延迟控制等。尤其是汽车自适应前照灯系统,它是一种能够自动改变两种以上的光型以适…...
Python Flask+Echarts+sklearn+MySQL(评论情感分析、用户推荐、BI报表)项目分享
Python FlaskEchartssklearnMySQL(评论情感分析、用户推荐、BI报表)项目分享 项目背景: 随着互联网的快速发展和智能手机的普及,人们越来越倾向于在网上查找餐厅、购物中心、酒店和旅游景点等商户的点评和评分信息,以便做出更好的消费决策。…...
开源项目-高校自动排课系统
哈喽,大家好,今天给大家带来一个开源项目-基于遗传算法的一个高校自动排课系统,同时也是一个前后端分离项目。 前端:React 后端:SpringBoot+MyBatis+MySQL数据库 高校自动排课系统的主要功能包括查询模块,安排教学区域,排课页面三部分 登录 查询模块 可以根据学年…...
IP网络广播系统草坪音箱景区系统防水石头,草坪音箱的应用
IP网络广播系统草坪音箱景区系统防水石头,草坪音箱的应用 SV-7045V是深圳锐科达电子有限公司的一款防水网络草坪音箱,具有10/100M以太网接口,可将网络音源通过自带的功放和喇叭输出播放,可达到功率20W。常用场景:公园ip草坪音箱&…...
拒绝摆烂!C语言练习打卡第二天
🔥博客主页:小王又困了 📚系列专栏:每日一练 🌟人之为学,不日近则日退 ❤️感谢大家点赞👍收藏⭐评论✍️ 目录 一、选择题 📝1.第一题 📝2.第二题 📝…...
第四章:前端框架Vue基础入门
文章目录 一、Vue框架概述1.1 声明响应式的数据 二、Vue内置指令2.1、条件渲染指令v-if/v-show2.2 v-for: 列表渲染2.3、v-text/v-html 模板指令2.4 v-on:事件监听器2.6 动态绑定v-bind2.7 v-model表单元素值绑定 三、计算属性与监视3.1 计算属性computed3.2 watch侦听器3.3 wa…...
企业权限管理(十三)-用户关联角色操作
用户关联角色操作 从前台发送请求 <a href"${pageContext.request.contextPath}/user/findUserByIdAndAllRole.do?id${user.id}" class"btn bg-olive btn-xs">添加角色</a>查询用户以及用户可以添加的角色 usercontroller //查询用户以及用…...
深入理解Vue 3.0x中的Suspense和异步组件
深入理解Vue 3.0x中的Suspense和异步组件 Vue 3.0x作为Vue.js框架的最新版本,引入了许多创新特性,其中Suspense和异步组件是重要的改进之一。在本文中,我们将深入探讨这两个特性,了解它们如何为现代Web应用带来更好的性能和用户体…...
Ajax 笔记(三)—— Ajax 原理
笔记目录 3. Ajax 原理3.1 XMLHttpRequest3.1.1 XHR 使用步骤3.1.2 查询参数3.1.3 数据提交 3.2 Promise3.2.1 Promise 使用步骤3.2.2 Promise 状态3.2.3 Promise 和 XHR 应用小案例 3.3 封装简易 axios3.3.1 核心封装代码3.3.2 支持传递查询参数3.3.3 支持传递请求体数据 Ajax…...
el-tree通过default-expand-all动态控制展开/折叠
1、如下图通过勾选框动态控制展开/折叠,全选/清空 2、实现方式如下:定义key,监听checked2修改treeKey,重新渲染tere;附加全选和清空。 <div class"tree"><el-checkbox v-model"checked1"…...
基于Bsdiff差分算法的汽车OTA升级技术研究(学习)
摘要 针对汽车OTA整包升级时,用户下载时间长,升级时间长,设备服务器端压力大等问题,本文提出了一种基于Bsdiff差分算法的汽车OTA升级技术。该算法能够对比新旧版本的差异,进行差分文件下载,减少软件包的下…...
如何使用CSS实现一个纯CSS的滚动条样式?
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 使用CSS实现自定义滚动条样式⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅!这个专栏是为那些对Web开发感兴趣…...
深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...
