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)
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')
})
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')
})