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()
一点、一点才能到达彼岸