tapable

2022-01-24  本文已影响0人  JerrySi

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
上一篇下一篇

猜你喜欢

热点阅读