乐趣区

关于webpack4:webpack底层工具库tapable基本使用

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会重头开始继续执行

异步钩子

对于异步钩子的应用,在增加事件监听时会存在三种形式:taptapAsynctapPromise
异步并行钩子: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')
})


从后果来看,代码是串行执行

退出移动版