动态

详情 返回 返回

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)

image.png
結果都能因此打印

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)

image.png
如果返回非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)

image.png
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)

image.png
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')
})

image.png

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

image.png
從執行結果來看,是並行執行

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

image.png

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

image.png
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')
})

image.png
從結果來看,代碼是串行執行

user avatar zaotalk 头像 woniuseo 头像 yuzhihui 头像 lin494910940 头像 joe235 头像 Asp1rant 头像 laggage 头像 jmix 头像 potato1314 头像 iymxpc3k 头像 haikuotiankong_mac 头像 patelo 头像
点赞 23 用户, 点赞了这篇动态!
点赞

Add a new 评论

Some HTML is okay.