tapable是一种事件驱动型事件流机制,本身是一个独立的库。webpack 通过 tapable 将实现与流程解耦,所有具体实现通过插件的形式存在。
一. 工作流程
1.实例化Hook注册事件监听
2.通过Hook触发事件监听
3.执行懒编译生成的可执行代码
二、 Hook
Hook的执行机制可分为同步和异步两种,其中异步又分为并行和串行两种模式。
Hook的钩子类型分为四种:
1. Hook:普通钩子,监听器之间互相独立不干扰
2. BailHook:熔断钩子,某个监听返回非undefined时后续不执行
3. WaterfallHook:瀑布钩子,上一个监听的返回值可传递至下一个
4. LoopHook:循环钩子,如果当前返回非undefined则一直执行(从头开始执行)(webpack中不常见)
三、同步钩子
- SyncHook
每个事件独立执行,互相不影响
const { SyncHook } = 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.call('jerry', 18)
// fn1---> jerry 18
// fn2---> jerry 18
- SyncBailHook
某个监听返回非undefined时后续不执行
const { SyncBailHook } = require('tapable')
let hook = new SyncBailHook(['name', 'age'])
hook.tap('fn1', function (name, age) {
console.log('fn1--->', name, age)
})
hook.tap('fn2', function (name, age) {
console.log('fn2--->', name, age)
return undefined
})
hook.tap('fn3', function (name, age) {
console.log('fn3--->', name, age)
})
hook.call('jerry', 100)
// fn1---> jerry 100
// fn2---> jerry 100
// fn3---> jerry 100
- SyncWaterfallHook
上一个监听的返回值可传递至下一个,覆盖原来的参数值
const { SyncWaterfallHook } = require('tapable')
let hook = new SyncWaterfallHook(['name', 'age'])
hook.tap('fn1', function (name, age) {
console.log('fn1--->', name, age)
return 'ret1'
})
hook.tap('fn2', function (name, age) {
console.log('fn2--->', name, age)
return 'ret2'
})
hook.tap('fn3', function (name, age) {
console.log('fn3--->', name, age)
return 'ret3'
})
hook.call('jerry', 33)
// fn1---> jerry 33
// fn2---> ret1 33
// fn3---> ret2 33
- SyncLoopHook
执行时,如果都没有返回,则执行一遍后就退出
如果有一个返回了非undefined,则从头重新开始执行
当遇到返回了undefined则执行完所有监听后退出
const { SyncLoopHook } = require('tapable')
let hook = new SyncLoopHook(['name', 'age'])
let count1 = 0
let count2 = 0
hook.tap('fn1', function (name, age) {
console.log('fn1--->', name, age)
if (++count1 === 1) {
count1 = 0
return undefined
}
return true
})
hook.tap('fn2', function (name, age) {
console.log('fn2--->', name, age)
if (++count2 === 2) {
count2 = 0
return undefined
}
return true
})
hook.tap('fn3', function (name, age) {
console.log('fn3--->', name, age)
})
hook.call('foo', 100)
// 不是undefined时候从上到下继续依次执行,直到返回undefined
// fn1---> foo 100
// fn2---> foo 100
// fn1---> foo 100
// fn2---> foo 100
// fn3---> foo 100
四、异步钩子
对于异步钩子的使用,在添加事件监听时会存在三种方式: tap、tapAsync、 tapPromise
- AsyncParalleHook 异步并行
const { AsyncParallelHook } = require('tapable')
let hook = new AsyncParallelHook(['name'])
// 对于异步钩子的使用,在添加事件监听时会存在三种方式: tap tapAsync tapPromise
// hook.tap('fn1', function (name) {
// console.log('fn1--->', name)
// })
// hook.tap('fn2', function (name) {
// console.log('fn2--->', name)
// })
// hook.callAsync('zoe', function () {
// console.log('最后执行了回调操作')
// })
/* 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('lg', function () {
console.log('最后一个回调执行了')
console.timeEnd('time')
}) */
// 03 promise
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('foo').then(() => {
console.log('end执行了')
console.timeEnd('time')
})
// fn1---> foo
// fn2---> foo
// end执行了
// time: 2.007s
- AsyncParallelBailHook 异步并行
const { AsyncParallelBailHook } = require('tapable')
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('zce', function () {
console.log('最后的回调执行了')
console.timeEnd('time')
})
// fn1---> zce
// fn2---> zce
// 最后的回调执行了
// time: 2.004s
// fn3---> zce 执行fn3是因为定时器到时间了,正常是不会执行的
- AsyncSeriesHook 异步串行。 其他异步串行还有AsyncSeriesBailHook、AsyncSeriesLoopHook、AsyncSeriesWaterfallHook。
const { AsyncSeriesHook } = require('tapable')
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('foo').then(function () {
console.log('~~~~')
console.timeEnd('time')
})
// fn1---> foo
// fn2---> foo
// ~~~~
// time: 3.029s
网友评论