• webpack之tapable


    webpack

    tapable

    webpack本质上是一种事件流的机制,它的工作流程就是将各个插件串联起来,而实现这一切的核心就是tapable,核心原理是依赖于发布订阅模式;
    tapable注册函数的方法有三种:tap、tapAsync、tapPromise
    相对应的执行方法也有三种:call、callAsync、promise

    SyncHook

    const { SyncLoopHook } = require('tapable')
    
    class Lesson {
      constructor () {
        this.index = 0
        this.hooks = {
          arch: new SyncLoopHook(['name'])
        }
      }
      tap () {
        let self = this
        this.hooks.arch.tap('node', function (name) {
          console.log('node', name)
          return ++self.index >=3 ? undefined :'23'
        })
        this.hooks.arch.tap('react', function (name) {
          console.log('react', name)
        })
      }
      start () {
        this.hooks.arch.call('jw')
      }
    }
    
    let l = new Lesson()
    l.tap()
    l.start()
    
    • SyncBailHook

    SyncBailHook同步熔断保险钩子,即return一个非undefined的值,则不再继续执行后面的监听函数

    • SyncWaterfallHook

    上一个监听函数的返回值会传递给下一个监听函数

    • SyncLoopHook

    遇到某个不返回undefined的监听函数,就重复执行


    AsyncHook

    const { AsyncParallelHook } = require('tapable')
    
    class Lesson {
      constructor () {
        this.index = 0
        this.hooks = {
          arch: new AsyncParallelHook(['name'])
        }
      }
      tap () {
        let self = this
        this.hooks.arch.tapAsync('node', function (name, cb) {
          setTimeout(() => {
            console.log('node', name)
            cb()
          })
        })
        this.hooks.arch.tapAsync('react', function (name, cb) {
          console.log('react', name)
          cb()
        })
      }
      start () {
        this.hooks.arch.callAsync('jw', function () {
          console.log('end')
        })
      }
    }
    
    let l = new Lesson()
    l.tap()
    l.start()
    
    结果:
    react jw
    node jw
    end
    
    • AsyncParallelHook

    异步 并行

    源码:

    module.exports =  class AsyncParallelHook {
      constructor () {
        this.tasks = []
      }
      tapAsync (name, fn) {
        this.tasks.push(fn)
      }
      callAsync (...args) {
        const final = args.pop()
        let index = 0
        const done = () => {
          index++
          if (index === this.tasks.length) {
            final()
          }
        }
        this.tasks.forEach(task => {
          task(...args, done)
        })
      }
    }
    
    • AsyncSeriesHook

    异步串行

    源码:

    // callback方式
    module.exports =  class AsyncSerieslHook {
      constructor () {
        this.tasks = []
      }
      tapAsync (name, fn) {
        this.tasks.push(fn)
      }
      callAsync (...args) {
        let index = 0
        const final = args.pop()
        const next = () => {
          if (this.tasks.length === index) {
            final()
            return
          }
          const firstFn = this.tasks[index++]
          firstFn(...args, next)
        }
        next()
      }
    }
    
    
    // promise方式
    module.exports =  class AsyncSerieslHook {
      constructor () {
        this.tasks = []
      }
      tapPromise (name, fn) {
        this.tasks.push(fn)
      }
      promise (...args) {
        const [firstFn, ...others] = this.tasks
        return others.reduce((n, p) => {
          return n.then(_ => p(...args))
        }, firstFn(...args))
      }
    }
    

    调用:

    //callback方式调用
    const AsyncSeriesHook = require('./asyncHook')
    
    class Lesson {
      constructor () {
        this.index = 0
        this.hooks = {
          arch: new AsyncSeriesHook(['name'])
        }
      }
      tap () {
        this.hooks.arch.tapAsync('node', function (name, cb) {
          setTimeout(() => {
            console.log('node', name)
            cb()
          }, 1000)
        })
        this.hooks.arch.tapAsync('react', function (name, cb) {
          setTimeout(() => {
            console.log('react', name)
            cb()
          }, 2000)
        })
      }
      start () {
        this.hooks.arch.callAsync('jw', function () {
          console.log('end')
        })
      }
    }
    
    let l = new Lesson()
    l.tap()
    l.start()
    
    // promise方式调用
    const AsyncSeriesHook = require('./asyncHook')
    
    class Lesson {
      constructor () {
        this.index = 0
        this.hooks = {
          arch: new AsyncSeriesHook(['name'])
        }
      }
      tap () {
        this.hooks.arch.tapPromise('node', function (name) {
          return new Promise((resolve, reject) => {
            setTimeout(() => {
              console.log('node', name)
              resolve()
            }, 1000)
          })
        })
        this.hooks.arch.tapPromise('react', function (name) {
          return new Promise((resolve, reject) => {
            setTimeout(() => {
              console.log('react', name)
              resolve()
            }, 2000)
          })
        })
      }
      start () {
        this.hooks.arch.promise('jw').then(function () {
          console.log('end')
        })
        // this.hooks.arch.callAsync('jw', function () {
        //   console.log('end')
        // })
      }
    }
    
    let l = new Lesson()
    l.tap()
    l.start()
    
    • AsyncSeriesWaterFallHook

    异步 串行 结果传递,错误处理


    callback方式:

    // callback 方式
    class Hook {
      constructor () {
        this.tasks = []
      }
      tapAsync(name, fn) {
        this.tasks.push(fn)
      }
      callAsync(...args) {
        let index = 0
        const final = args.pop()
        const next = (err, data) => {
          const task = this.tasks[index]
          if (!task) return final()
          if (index === 0) {
            task(...args, next)
          } else if (index > 0) {
            if (!err && data) {
              task(data, next)
            }
            if (!err && !data) {
              task(...args, next)
            }
            if (err) {
              final(err)
            }
          }
          index++
        }
        next()
      }
    }
    
    module.exports = Hook
    
    // 调用
    // const { AsyncSeriesWaterfallHook } = require('tapable')
    const AsyncSeriesWaterfallHook = require('./hook')
    
    class Lesson {
      constructor () {
        this.hooks = {
          arch: new AsyncSeriesWaterfallHook()
        }
      }
    
      tap () {
        this.hooks.arch.tapAsync('lesson1', function (name, cb) {
          setTimeout(() => {
            console.log('lesson1', name)
            /** 第一次参数是err, 第二个参数是传递给下一步的参数 */
            cb(null, 'werw')
          }, 1000)
        })
        this.hooks.arch.tapAsync('lesson2', function (name, cb) {
          setTimeout(() => {
            console.log('lesson2', name)
            cb()
          }, 2000)
        })
      }
      call () {
        this.hooks.arch.callAsync(['rain'], (err) => {
          console.log(err)
          console.log('end')
        })
      }
    }
    
    const le = new Lesson()
    
    le.tap()
    le.call()
    
    

    promise方式:

    // promise方式
    
    class Hook {
      constructor () {
        this.tasks = []
      }
      tapPromise(name, fn) {
        this.tasks.push(fn)
      }
      promise(...args) {
        const [first, ...others] = this.tasks
        return others.reduce((p, n) => p.then(_ => n(_)), first(...args))
      }
    }
    
    module.exports = Hook
    
    // 调用
    
    // const { AsyncSeriesWaterfallHook } = require('tapable')
    const AsyncSeriesWaterfallHook = require('./hook')
    
    class Lesson {
      constructor () {
        this.hooks = {
          arch: new AsyncSeriesWaterfallHook()
        }
      }
    
      tap () {
        this.hooks.arch.tapPromise('lesson1', function (name) {
          return new Promise((resolve, reject) => {
            setTimeout(() => {
              console.log('lesson1', name)
              /** 第一次参数是err, 第二个参数是传递给下一步的参数 */
              resolve('aa')
            }, 1000)
          })
        })
        this.hooks.arch.tapPromise('lesson2', function (name) {
          return new Promise((resolve, reject) => {
            setTimeout(() => {
              console.log('lesson2', name)
              resolve()
            }, 2000)
          })
        })
      }
      call () {
        this.hooks.arch.promise(['rain']).then((data) => {
          console.log(data)
          console.log('end')
        })
      }
    }
    
    const le = new Lesson()
    
    le.tap()
    le.call()
    
    
  • 相关阅读:
    javaScript 基础知识汇总(六)
    javaScript 基础知识汇总(五)
    javaScript 基础知识汇总(四)
    WPF — Grid布局中行的高度和列的高度值定义的三种形式
    C# — 用递归实现斐波拉契数列的第n项
    C# — ref参数、params参数、out参数详解
    Android apk反编译教程
    WPF学习资源
    C# — 通过点击回车执行任务
    C# — MvvMLight框架入门资源
  • 原文地址:https://www.cnblogs.com/raind/p/13020567.html
Copyright © 2020-2023  润新知