tapable工作流程
- 實例化hook註冊事件監聽
- 通過hook觸發事件監聽
- 執行懶編譯生成的可執行代碼
Hook本職是tapable實例對象,分同步和異步,異步分並行和串行兩種模式
Hook執行特點
Hook:普通鈎子,監聽器之間互相獨立不干擾
BailHook:熔斷鈎子,某個監聽返回非undefined時後續不執行
WaterfallHoook: 瀑布鈎子,上一個監聽的返回值可傳遞至下一個
LoopHook:循環鈎子,如果當前未返回false則一直執行
tapable庫同步鈎子:SynckHook,SyncBailHoook,SyncWaterfallHook,SyncLoopHook
異步串行鈎子:AsyncSeriesHoook,AsyncSeriesBailHook,AsyncSeriesWaterfallHook,異步並行鈎子:AsyncParallerHook,AsyncParalleBailHook
同步鈎子:
SyncHook
let {
SyncHook,
SyncBailHook
} = require('tapable')
// 創建鈎子
let hook = new SyncHook(['name', 'age'])
hook.tap('fn1', function (name, age) {
console.log('fn1', name, age)
})
hook.tap('fn2', function (name, age) {
console.log('fn2', name, age)
})
hook.tap('fn3', function (name, age) {
console.log('fn3', name, age)
})
hook.call('jack', 18)
結果都能因此打印
SyncBailHook
let bailHook = new SyncBailHook(['name', 'age'])
bailHook.tap('fn1', function (name, age) {
console.log('fn1', name, age)
})
bailHook.tap('fn2', function (name, age) {
console.log('fn2', name, age)
return 'tom' // fn1,fn2,會打印,fn3不會打印
// return undefined // fn1,fn2,fn3都會打印
})
bailHook.tap('fn3', function (name, age) {
console.log('fn3', name, age)
})
bailHook.call('jack', 18)
如果返回非undefined,流程就會終止
SyncWaterfallHook
let waterfallhook = new SyncWaterfallHook(['name', 'age'])
waterfallhook.tap('fn1', function (name, age) {
console.log('fn1', name, age)
return 'fn1'
})
waterfallhook.tap('fn2', function (name, age) {
console.log('fn2', name, age)
return 'fn2'
})
waterfallhook.tap('fn3', function (name, age) {
console.log('fn3', name, age)
return 'fn3'
})
waterfallhook.call('jack', 18)
SyncWaterfallHook可以通過return把返回值傳遞給下一個鈎子
SyncLoopHook
let loophook = new SyncLoopHook(['name', 'age'])
let cnt1 = 0
let cnt2 = 0
let cnt3 = 0
loophook.tap('fn1', function (name, age) {
console.log('fn1', name, age)
if (++cnt1 === 2) {
cnt1 === 0
return undefined
}
return true
})
loophook.tap('fn2', function (name, age) {
console.log('fn2', name, age)
})
loophook.tap('fn3', function (name, age) {
console.log('fn3', name, age)
})
loophook.call('jack', 18)
tap函數體內設置了判斷條件,如果不滿足條件,SyncLoopHook會重頭開始繼續執行
異步鈎子
對於異步鈎子的使用,在添加事件監聽時會存在三種方式:tap、 tapAsync、 tapPromise
異步並行鈎子:AsyncParallerHook
tap方式監聽
let hook = new AsyncParallelHook(['name'])
hook.tap('fn1', function (name) {
console.log('fn1', name)
})
hook.tap('fn2', function (name) {
console.log('fn2', name)
})
hook.callAsync('jack', function () {
console.log('operate async')
})
tapAsync方式監聽
console.time('time')
hook.tapAsync('fn1', function (name, callback) {
setTimeout(() => {
console.log('fn1', name)
callback()
}, 1000);
})
hook.tapAsync('fn2', function (name, callback) {
setTimeout(() => {
console.log('fn2', name)
callback()
}, 2000);
})
hook.callAsync('jack', function () {
console.log('operate tapAsync')
console.timeEnd('time')
})
從執行結果來看,是並行執行
tapPromise方式監聽
console.time('time')
hook.tapPromise('fn1', function (name) {
return new Promise(function (resolve, reject) {
setTimeout(() => {
console.log('fn1', name)
resolve()
}, 1000);
})
})
hook.tapPromise('fn2', function (name) {
return new Promise(function (resolve, reject) {
setTimeout(() => {
console.log('fn2', name)
resolve()
}, 2000);
})
})
hook.promise('jack').then(() => {
console.log('end')
console.timeEnd('time')
})
AsyncParallelBailHook
let hook = new AsyncParallelBailHook(['name']);
console.time('time')
hook.tapAsync('fn1', function (name, callback) {
setTimeout(() => {
console.log('fn1', name)
callback()
}, 1000);
})
hook.tapAsync('fn2', function (name, callback) {
setTimeout(() => {
console.log('fn2', name)
callback('err') // 熔斷操作
}, 2000);
})
hook.tapAsync('fn3', function (name, callback) {
setTimeout(() => {
console.log('fn3', name)
callback()
}, 3000);
})
hook.callAsync('jack', function () {
console.log('end')
console.timeEnd('time')
})
fn3最後是執行了,但是在fn2後就熔斷了.
AsyncSeriesHook串行
let hook = new AsyncSeriesHook(['name'])
console.time('time')
hook.tapPromise('fn1', function (name) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('fn1', name)
resolve()
}, 1000);
})
})
hook.tapPromise('fn2', function (name) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('fn2', name)
resolve()
}, 2000);
})
})
hook.promise('fn').then(function () {
console.log('end')
console.timeEnd('time')
})
從結果來看,代碼是串行執行