• webpack4.X核心工具库之tapable实例对象Hook


    一.tapable简介

    tapable为webpack底层的核心工具库,webpack许多功能的实现都是跟它密不可分的,webpack的编译流程为配置初始化--->内容编译--->输出编译后内容,这三个的整体执行过程可以称之为

    事件驱动型事件流工作机制,这个机制将不同的工作流串联起来完成所有的工作,其中最为核心的两个部分是 负责编译的complier 负责创建bundles的compilation。tapable本身是一个独立的库

    在webpack中进行了大量的使用,tapable工作流程是 实例化hook注册事件监听---->通过hook触发事件监听---->执行懒编译生成的可执行代码。

    二.Hook简介

    Hook本质是tapable实例对象,hook执行机制可分为同步和异步,对于异步来说又存在着并行和串行两种,其中hook的执行特点如下:

    Hook:普通钩子,监听器之间互相独立不干扰。

    BailHook:熔断钩子,某个监听返回非undefined时后续不执行。

    WaterfallHook:瀑布沟子,上一个监听返回值可传递至下一个。

    LoopHook:循环钩子,如果当前未返回false则一直执行。

    tapable库同步钩子分为SynckHook,SyncBailHook,SyncWaterfallHook,SyncLoopHook。

    tapable库异步串行钩子分为AsyncSeriesHook,AsyncSeresBailHook,AsynvSeriesWaterfallHook。

    tapable库异步并行钩子分为AsyncParalleHook,AsyncParalleBailHook。

    三.同步钩子的使用

    1.同步钩子之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)
                    return 'res'
                })
                hook.tap('fn3',function(name,age){
                    console.log('fn3---->',name,age)
                })
                //触发监听
                hook.call('lw','18') 
    //打印结果为 fn1-----> lw 18 fn2-----> lw 18 fn3-----> lw 18

    上述代码中即便fn2 return了后面的fn3依然会执行。

    2.同步钩子之syncBialHook

                     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 'res'
                     })
                     hook.tap('fn3',function(name,age){
                         console.log('fn3---->',name,age)
                     })
                     //触发监听
                     hook.call('lw','100') 
    //打印结果为 fn1-----> lw 18 fn2-----> lw 18

    上述代码中与SyncHook不同的是fn2中添加一个return (非undefined) 后面的fn3不会执行,说明这条流水线断掉了

    3.同步钩子之syncWaterfallHooks

                    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('lw','100') 
    //打印结果为 fn1-----> lw 18 fn2-----> ret1 18 fn3-----> ret2 18

    这个钩子的特点是通过上一个监听返回的ret1传给下一个钩子函数fn2 然后返回 依次类推 所以又叫瀑布沟子

    4.同步钩子之SyncLoopHook

                    const { SyncLoopHook } =require('tapable')
                    //钩子实例
                    let hook =new SyncLoopHook(['name','age'])
                    let count1=0
                    let count2=0
                    let count3=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('lw','100') 
    //打印结果为:fn1-----> lw 18 fn2-----> lw 18 fn1-----> lw 18 
    //fn2-----> lw 18 fn3-----> lw 18

    从打印结果可以看出循环执行了2遍,第一次执行到了fn2停止,第二次3个函数执行完经调试代码得知底层是一个

    do while循环,while的重新执行条件为return内容为true。

    四.异步钩子的使用

    对于异步钩子的使用,在添加事件监听时会存在三种方式:tap tapAsync tapPromise。

    1.tapable库异步并行钩子
    //第一种方式 tap
                    const { AsyncParallelHook } =require('tapable')
                    //钩子实例
                    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('lw',function(){
                        console.log('回调操作最后执行')
                    })
    //打印结果 fn1---->lw fn2----->lw  最后执行回调

    并行钩子的tap方法是同步进行的,只是从打印结果的话很难看出同步进行,下面通过另一种方式

    改动下看下效果。

     //第二种方式 tapAsync
     //通过settimeOut异步操作,如果为并行执行的话,执行结果应该偏向于大的时间数值,
    //我们用console.time标记下,代码如下:
    const { AsyncParallelHook } =require('tapable') //钩子实例 let hook =new AsyncParallelHook(['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() },2000) }) hook.callAsync('lw',function(){ console.log('回调操作最后执行') console.timeEnd('time') }) //打印结果为fn1--->lw fn2--->lw
    //同步打印出来 time:2.002s 所以证明是并行执行
    //第三种方式 tapPromise
                    const { AsyncParallelHook } =require('tapable')
                    //钩子实例
                    let hook =new AsyncParallelHook(['name'])
                    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('lw').then(()=>{
                        console.log('end执行了')
                        console.timeEnd('time')
                    })
    //打印结果为fn1--->lw fn2--->lw 
    //同步打印出来 time:2.002s 同样并行执行
           //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('lw',function(){
                        console.log('最后的回调执行了')
                        console.timeEnd('time')
                    })
    //打印结果为fn1---->lw fn2--->lw 
    //最后函数回调执行了 time:2.002s fn3--->lw
    从打印结果来看fn2里面callback('err') 返回错误 所以在fn2进行时阻断掉了,总运行时长接近2s

    最后fn3也打印出来是因为终归有个settimeout控制着所以到达3s会被打印。

    2.tapable库异步串行钩子
                   const { AsyncSeriesHook } =require('tapable')
                    //钩子实例
                    let hook =new AsyncSeriesHook(['name'])
                    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('lw').then(()=>{
                        console.log('end执行了')
                        console.timeEnd('time')
                    })
    //打印结果为fn1--->lw fn2--->lw time:3.002s(1s+2s)
    //串行和我们的同步钩子是很接近的,只不过多了一步回调操作
    /*****************************************************/
    “如约而至”是个多么美好的词,等的辛苦,却从不辜负。
    ---感谢阅读,o(* ̄︶ ̄*)o开心每一天!
  • 相关阅读:
    把Outlook与Google Calendar同步了
    (int) Int32.Parse() Convert.toInt32() (转)
    Http Context(转)
    DataReader DataSet(转)
    主键和外键(转)
    显卡参数学习
    开源抽象工厂模式,序列化,反序列化等..
    ASP.NET中App_Code,App_Data等文件夹的作用(转)
    using tianjiayinyong qubie
    xuliehua fanxuliehua xml(zhuan)
  • 原文地址:https://www.cnblogs.com/websiteblogs/p/14431707.html
Copyright © 2020-2023  润新知