异步并行, 监听的函数会一块执行, 哪个函数先执行完就先触发。不需要关心监听函数的返回值。
class AsyncParallelHook { constructor(options) { this.options = options this.asyncHooks = [] } // 订阅 tapAsync(name, callback) { this.asyncHooks.push(callback) } // 发布 callAsync(...args) { /** * callAsync(arg1, arg2,..., cb) * 发布的时候最后一个参数可以是回调函数 * 订阅的每一个函数的最后一个参数也是一个回调函数,所有的订阅函数执行完 * 且都调用了最后一个函数,才会执行cb */ const finalCallback = args.pop() let i = 0 // 将这个作为最后一个参数传过去,使用的时候选择性调用 const done = () => { ++i === this.asyncHooks.length && finalCallback() } this.asyncHooks.forEach(hook => { hook(...args, done) }) } } const asyncParallelHook = new AsyncParallelHook('name') asyncParallelHook.tapAsync('name', (data, done) => { setTimeout(() => { console.log('name', data) done() }, 2000) }) asyncParallelHook.tapAsync('age', (data, done) => { setTimeout(() => { console.log('age', data) done() }, 3000) }) console.time('time') asyncParallelHook.callAsync('qiqingfu', () => { console.log('监听函数都调用了 done') console.timeEnd('time') })打印结果
name qiqingfu age qiqingfu 监听函数都调用了 done time: 3002.691ms AsyncParalleBailHook 暂时不理解 AsyncSeriesHook异步串行钩子类, 不关心 callback的参数。异步函数一个一个的执行,但是必须调用 done函数。
class AsyncSeriesHook { constructor(options) { this.options = options this.asyncHooks = [] } tapAsync(name, callback) { this.asyncHooks.push(callback) } callAsync(...args) { const finalCallback = args.pop() let i = 0 const done = () => { let task = this.asyncHooks[i++] task ? task(...args, done) : finalCallback() } done() } } const asyncSeriesHook = new AsyncSeriesHook('name') asyncSeriesHook.tapAsync('name', (data, done) => { setTimeout(() => { console.log('name', data) done() }, 1000) }) asyncSeriesHook.tapAsync('age', (data, done) => { setTimeout(() => { console.log('age', data) done() }, 2000) }) console.time('time') asyncSeriesHook.callAsync('qiqingfu', () => { console.log('end') console.timeEnd('time') })执行结果
name qiqingfu age qiqingfu end time: 3010.915ms AsyncSeriesBailHook同步串行钩子类, callback的参数如果不是 null, 后面所有的异步函数都不会执行,直接执行 callAsync方法的回调函数
class AsyncSeriesBailHook { constructor(options) { this.options = options this.asyncHooks = [] } tapAsync(name, callback) { this.asyncHooks.push(callback) } callAsync(...args) { const finalCallback = args.pop() let i = 0 const done = data => { if (data) return finalCallback() let task = this.asyncHooks[i++] task ? task(...args, done) : finalCallback() } done() } } const asyncSeriesBailHook = new AsyncSeriesBailHook('name') asyncSeriesBailHook.tapAsync('1', (data, done) => { setTimeout(() => { console.log('1', data) done(null) }, 1000) }) asyncSeriesBailHook.tapAsync('2', (data, done) => { setTimeout(() => { console.log('2', data) done(null) }, 2000) }) console.time('times') asyncSeriesBailHook.callAsync('qiqingfu', () => { console.log('end') console.timeEnd('times') })打印结果
1 qiqingfu 2 qiqingfu end times: 3012.060ms AsyncSeriesWaterfallHook同步串行钩子类, 上一个监听函数 callback(err, data)的第二个参数, 可以作为下一个监听函数的参数
class AsyncSeriesWaterfallHook { constructor(options) { this.options = options this.asyncHooks = [] } tapAsync(name, callback) { this.asyncHooks.push(callback) } callAsync(...args) { const finalCallback = args.pop() let i = 0, once const done = (err, data) => { let task = this.asyncHooks[i++] if (!task) return finalCallback() if (!once) { // 只执行一次 task(...args, done) once = true } else { task(data, done) } } done() } } const asyncSeriesWaterfallHook = new AsyncSeriesWaterfallHook('name') asyncSeriesWaterfallHook.tapAsync('1', (data, done) => { setTimeout(() => { console.log('1', data) done(null, '第一个callback传递的参数') }, 1000) }) asyncSeriesWaterfallHook.tapAsync('2', (data, done) => { setTimeout(() => { console.log('2', data) done(null) }, 1000) }) console.time('timer') asyncSeriesWaterfallHook.callAsync('qiqingfu', () => { console.log('end') console.timeEnd('timer') })打印结果
1 qiqingfu 2 第一个callback传递的参数 end timer: 2015.445ms END如果理解有误, 麻烦纠正!
参考文章webpack4.0源码分析之Tapable
webpack 4.0 Tapable 类中的常用钩子函数源码分析