tapable 库使用和原理分析

发布于 2022-09-20 23:08:46 字数 6252 浏览 106 评论 0

webpack 源码中使用这个库来事件流程。

tapable 库中有三种注册方法,tab 同步注册,tabAsync 异步注册(回调方式),tapPromise 异步注册(promise 方式)
调用也是三种方式,call 同步调用,callAsync 异步调用,promise 异步调用

同步注册

let {SyncHook} = require('tapable');

class Lesson {
  constructor () {
    this.hooks = {
      arch: new SyncHook(['name'])
    }
  }
  tap () {
    this.hooks.arch.tap('node', function (name) {
      console.log(`${name}学习node课程`)
    });
    this.hooks.arch.tap('react', function (name) {
      console.log(`${name}学习react课程`)
    });
  }
  start () {
    this.hooks.arch.call('张三')
  }
}

let lesson = new Lesson();
lesson.tap();
lesson.start();
console.log('学习完成')

原理

class SyncHook {
  constructor (args) {
    this.tasks = [];
  }
  call (...args) {
    this.tasks.forEach(task => task(...args))
  }
  tap (name, task) {
    this.tasks.push(task)
  }
}

异步回调注册

let {AsyncParallelHook} = require('tapable')

class Lesson {
  constructor () {
    this.hooks = {
      arch: new AsyncParallelHook(['name'])
    }
  }
  tap () {
    this.hooks.arch.tapAsync('node', function (name, cb) {
      setTimeout(() => {
        console.log(`${name}学习node课程`)
        cb();
      }, 1000);
    });
    this.hooks.arch.tapAsync('react', function (name, cb) {
      setTimeout(() => {
        console.log(`${name}学习react课程`)
        cb();
      }, 1000);
    });
  }
  start () {
    this.hooks.arch.callAsync('张三', () => {
      console.log('学习完成')
    })
  }
}

原理

class AsyncParallelHook {
  constructor (args) {
    this.tasks = [];
  }
  callAsync (...args) {
    let finalCallback = args.pop();
    let index = 0;
    const done = () => {
      index++;
      if (index === this.tasks.length) {
        finalCallback()
      }
    }
    this.tasks.forEach(task => {
      task(...args, done)
    })
  }
  tapAsync (name, task) {
    this.tasks.push(task)
  }
}

异步 promise 注册

let {AsyncParallelHook} = require('tapable')

class Lesson {
  constructor () {
    this.hooks = {
      arch: new AsyncParallelHook(['name'])
    }
  }
  tap () {
    this.hooks.arch.tapPromise('node', function (name) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log(`${name}学习node课程`)
          resolve()
        }, 1000);
      })
    });
    this.hooks.arch.tapPromise('react', function (name) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log(`${name}学习react课程`)
          resolve()
        }, 1000);
      })
    });
  }
  start () {
    this.hooks.arch.promise('张三').then(() => {
      console.log('学习完成')
    })
  }
}

原理

class AsyncParallelHook {
  constructor (args) {
    this.tasks = [];
  }
  promise(...args) {
    let tasks = this.tasks.map(task => task(...args));
    return Promise.all(tasks)
  }
  tapPromise (name, task) {
    this.tasks.push(task)
  }
}

上面包含两种异步处理方式都是异步并发的,并不能保证执行的先后顺序,那么接下来介绍异步并行执行的钩子函数。

异步串行回调形式

class Lesson {
  constructor() {
    this.hooks = {
      arch: new AsyncSeriesHook(['name'])
    }
  }
  tap() {
    this.hooks.arch.tapAsync('node', function (name, cb) {
      setTimeout(() => {
        console.log(`${name}学习node课程`)
        cb()
      }, 1000);
    });
    this.hooks.arch.tapAsync('react', function (name, cb) {
      setTimeout(() => {
        console.log(`${name}学习react课程`)
        cb()
      }, 1000);
    })
  }
  start() {
    this.hooks.arch.callAsync('张三', () => {
      console.log('学习完成')
    })
  }
}

原理(express 的 next 方法实现类似)

class AsyncSeriesHook {
  constructor (args) {
    this.tasks = [];
  }
  callAsync(...args) {
    let finalCallback = args.pop()
    let index = 0;
    let next = () => {
      if (this.tasks.length === index) return finalCallback();
      let task = this.tasks[index++];
      task(...args, next)
    }
    next()
  }
  tapAsync (name, task) {
    this.tasks.push(task)
  }
}

异步串行 promise 形式

class Lesson {
  constructor () {
    this.hooks = {
      arch: new AsyncSeriesHook(['name'])
    }
  }
  tap () {
    this.hooks.arch.tapPromise('node', function (name) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log(`${name}学习node课程`)
          resolve()
        }, 1000);
      })
    });
    this.hooks.arch.tapPromise('react', function (name) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log(`${name}学习react课程`)
          resolve()
        }, 1000);
      })
    });
  }
  start () {
    this.hooks.arch.promise('张三').then(() => {
      console.log('学习完成')
    })
  }
}

原理(redux 中间件原理类似)

class AsyncSeriesHook {
  constructor(args) {
    this.tasks = [];
  }
  promise(...args) {
    let [first, ...others] = this.tasks;
    return others.reduce((p, n) => {
      return p.then(() => n(...args))
    }, first(...args))
  }
  tapPromise(name, task) {
    this.tasks.push(task)
  }
}

异步瀑布流串行形式

意思是一个出错了会终端后续执行

let { AsyncSeriesWaterfallHook } = require('tapable')

class Lesson {
  constructor() {
    this.hooks = {
      arch: new AsyncSeriesWaterfallHook(['name'])
    }
  }
  tap() {
    this.hooks.arch.tapAsync('node', function (name, cb) {
      setTimeout(() => {
        console.log(`${name}学习node课程`)
        cb(null, 'data')
      }, 1000);
    });
    this.hooks.arch.tapAsync('react', function (data, cb) {
      setTimeout(() => {
        console.log(data)
        cb()
      }, 1000);
    })
  }
  start() {
    this.hooks.arch.callAsync('张三', () => {
      console.log('学习完成')
    })
  }
}

原理

class AsyncSeriesWaterfallHook {
  constructor (args) {
    this.tasks = [];
  }
  callAsync(...args) {
    // 类似于express的next
    let finalCallback = args.pop()
    let index = 0;
    let next = (err, data) => {
      let task = this.tasks[index++];
      if (!task) return finalCallback();
      if (index === 0) {
        task(...args, next)
      } else {
        task(data, next)
      }
      index++
    }
    next()
  }
  tapAsync (name, task) {
    this.tasks.push(task)
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

国粹

暂无简介

文章
评论
27 人气
更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

更多

友情链接

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文