tapable

作者: JerrySi | 来源:发表于2022-01-24 23:25 被阅读0次

    tapable是一种事件驱动型事件流机制,本身是一个独立的库。webpack 通过 tapable 将实现与流程解耦,所有具体实现通过插件的形式存在。

    一. 工作流程
    1.实例化Hook注册事件监听
    2.通过Hook触发事件监听
    3.执行懒编译生成的可执行代码

    二、 Hook
    Hook的执行机制可分为同步和异步两种,其中异步又分为并行和串行两种模式。

    Hook的钩子类型分为四种:
    1. Hook:普通钩子,监听器之间互相独立不干扰
    2. BailHook:熔断钩子,某个监听返回非undefined时后续不执行
    3. WaterfallHook:瀑布钩子,上一个监听的返回值可传递至下一个
    4. LoopHook:循环钩子,如果当前返回非undefined则一直执行(从头开始执行)(webpack中不常见)

    三、同步钩子

    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)
    })
    
    hook.call('jerry', 18)
    
    // fn1---> jerry 18
    // fn2---> jerry 18
    
    1. 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
    
    1. 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
    
    1. 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

    1. 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
    
    1. 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是因为定时器到时间了,正常是不会执行的
    
    1. 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
    

    相关文章

      网友评论

          本文标题:tapable

          本文链接:https://www.haomeiwen.com/subject/bomihrtx.html