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')
})
从后果来看,代码是串行执行