Tapable 的使用
Tapable 本身不能使用鲁森,只能使用從它導(dǎo)出的 Hook
const {
SyncHook,
SyncBailHook,
SyncWaterfallHook,
SyncLoopHook,
AsyncSeriesHook,
AsyncSeriesBailHook,
AsyncSeriesWaterfallHook,
AsyncParallelHook,
AsyncParallelBailHook,
} = require('tapable');
Hook 可以按照兩種標(biāo)準(zhǔn)來分類
- 事件回調(diào)的運(yùn)行邏輯:
- Basic:基本類型,按順序執(zhí)行注冊(cè)的回調(diào)
- Bail:保險(xiǎn)類型振惰,當(dāng)一個(gè)事件回調(diào)的返回值不為 undefined 時(shí)刀森,停止后面的回調(diào)執(zhí)行
- Waterfall:瀑布類型,如果當(dāng)前事件回調(diào)的返回值不為 undefined报账,那么返回值就作為下一個(gè)回調(diào)的第一個(gè)參數(shù)
- Loop:循環(huán)類型,如果當(dāng)前事件回調(diào)的返回值不為 undefined埠偿,回到第一個(gè)事件注冊(cè)的回調(diào)執(zhí)行透罢,直到所有的回調(diào)都返回 undefined(沒有返回)
- 觸發(fā)事件的方式:
- Sync:以 sync 開頭的 hook,同步的執(zhí)行注冊(cè)的事件冠蒋;只能使用 tap 方法注冊(cè)羽圃,使用 tapAsync 或 tapPromise 注冊(cè)會(huì)報(bào)錯(cuò)
- AsyncSerise:以 asyncSerise 開頭的 hook,按順序的執(zhí)行事件回調(diào)抖剿,如果回調(diào)是異步的朽寞,等異步執(zhí)行完成才會(huì)執(zhí)行下一個(gè)事件回調(diào);可以使用 tap斩郎、tapAsync脑融、tapPromise 注冊(cè)事件回調(diào);不能使用 call() 方法觸發(fā)回調(diào)
- AsyncParalle:以 asyncParalle 開頭的 hook缩宜,并行的執(zhí)行所有的事件回調(diào)
Sync hook
// 實(shí)例化 Hook
const { SyncHook } = require('tapable');
// 實(shí)例化鉤子類時(shí)傳入的數(shù)組肘迎,實(shí)際上只用上了數(shù)組的長(zhǎng)度,名稱是為了便于維護(hù)
const hook = new SyncHook(['name']);
// 事件注冊(cè)
hook.tap('first', (name) => {
console.log('first ', name);
});
// 第一個(gè)參數(shù)可以是事件回調(diào)的名字锻煌,也可以是配置對(duì)象
hook.tap({name: 'second'}, (name) => {
console.log('second ', name);
});
//觸發(fā)
hook.call('jack'); // 對(duì)應(yīng) sync hook
/**
* Console output:
*
* first jack
* second jack
*/
AsyncSerise hook
const { AsyncSeriesHook } = require('tapable');
const hook = new AsyncSeriesHook(['name']);
// 事件回調(diào)接收到 callback
hook.tapAsync('first', (name, callback) => {
console.log('first', name, callback);
callback();
});
// 最后一個(gè)傳入?yún)?shù)是回調(diào)函數(shù)
hook.callAsync('callAsync', (error) => {
console.log('callAsync', error);
});
/**
* Console output:
*
* first callAsync [Function]
* callAsync undefined
*/
callAsync 的第二個(gè)參數(shù):錯(cuò)誤回調(diào)callback
- 事件回調(diào)中必須調(diào)用 callback妓布,才能執(zhí)行下一個(gè)事件回調(diào)
- 調(diào)用 callback 時(shí)不傳入?yún)?shù)時(shí)執(zhí)行下一個(gè)回調(diào),傳入第一個(gè)參數(shù)代表有錯(cuò)誤發(fā)生宋梧,接下來會(huì)執(zhí)行觸發(fā)時(shí)的回調(diào)
Async hook 使用 tapPromise 注冊(cè)
const { AsyncSeriesHook } = require('tapable');
const hook = new AsyncSeriesHook(['name']);
hook.tapPromise('first', (name) => {
console.log('first', name);
return Promise.resolve('first');
});
hook.tapPromise('second', (name) => {
console.log('second', name);
return Promise.resolve('second');
});
const promise = hook.promise('promise');
console.log(promise);
promise.then(value => {
// value 是 undefined匣沼,不會(huì)接收到事件回調(diào)中傳入的值
console.log('value', value);
}, reason => {
// 事件回調(diào)返回的 Promise 對(duì)象狀態(tài)是 Rejected
// reason 會(huì)有事件回調(diào)中傳入的錯(cuò)誤信息
console.log('reason', reason);
});
/**
* Console output:
*
* first promise
* Promise { <pending> } // 同步代碼
* second promise // tapPromise 是微任務(wù),所以會(huì)在同步代碼后執(zhí)行
* value undefined
*/
promise 執(zhí)行之后會(huì)返回一個(gè) Promise 對(duì)象捂龄。在使用 tapPromise 注冊(cè)事件回調(diào)時(shí)释涛,事件回調(diào)必須返回一個(gè) Promise 對(duì)象,否則會(huì)報(bào)錯(cuò)倦沧,這是為了確保事件回調(diào)能夠按照順序執(zhí)行枢贿。
攔截器
我們可以給鉤子類添加攔截器,這樣就能對(duì)事件回調(diào)的注冊(cè)刀脏、調(diào)用以及事件的觸發(fā)進(jìn)行監(jiān)聽
const { SyncHook } = require('tapable');
const hook = new SyncHook();
hook.intercept({
// 注冊(cè)時(shí)執(zhí)行
register(tap) {
console.log('register', tap);
return tap;
},
// 觸發(fā)事件時(shí)執(zhí)行
call(...args) {
console.log('call', args);
},
// 在 call 攔截器之后執(zhí)行
loop(...args) {
console.log('loop', args);
},
// 事件回調(diào)調(diào)用前執(zhí)行
tap(tap) {
console.log('tap', tap);
},
});