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()