- Hook 基类,负责通用方法实现
class Hook {
constructor(args = []) {
this.args = args
// 用于存储所有的tap对象
this.taps = []
// 用于存储所有的tap里面的fn
// 代码工厂负责赋值
this._x = undefined
}
tap(option, fn) {
if (typeof option === 'string') {
option = {name: option}
}
// 合并
option = Object.assign({fn}, option)// { fn:... name:fn1 }
// 调用以下方法将组装好的 options 添加至 []
this._insert(option)
}
call(...args) {
// 01 创建将来要具体执行的函数代码结构
let callFn = this._createCall()
// 02 调用上述的函数(args传入进去)
return callFn.apply(this, args)
}
_createCall() {
return this.compile({
taps: this.taps,
args: this.args
})
}
_insert(options) {
this.taps[this.taps.length] = options
}
}
module.exports = Hook
- HookCodeFactory & SyncHook
HookCodeFactory 代码构建
SyncHook 子类
let Hook = require("./Hook.js")
class HookCodeFactory {
args() {
return this.options.args.join(',')
}
head() {
return 'var _x = this._x;'
}
content() {
let code = ''
for (let i = 0; i < this.options.taps.length; i++) {
code += `var _fn${i} = _x[${i}]; _fn${i}(${this.args()});`
}
return code;
}
init(options) {
this.options = options
}
// instance就是Hook
// options: {taps: [{}, {}], args: [name, age]}
setup(instance, options) {
// this._x = [f1, f2, ....]
instance._x = options.taps.map(o => o.fn)
}
// 核心就是创建一段可执行的代码体然后返回
create(options) {
this.init(options)
let fn
// fn = new Function("name, age", "var _x = this._x, var _fn0 = _x[0]; _fn0(name, age);")
fn = new Function(
this.args(),
this.head() + this.content()
)
return fn
}
}
let factory = new HookCodeFactory()
class SyncHook extends Hook {
constructor(args) {
super(args)
}
// {taps: [{}, {}], args: [name, age]}
compile(options) {
factory.setup(this, options)
return factory.create(options)
}
}
module.exports = SyncHook
- HookCodeFactory & AsyncParallelHook
AsyncParallelHook主要是要处理下callback
let Hook = require('./Hook.js')
class HookCodeFactory {
args({ after, before } = {}) {
let allArgs = this.options.args
if (before) allArgs = [before].concat(allArgs)
if (after) allArgs = allArgs.concat(after)
return allArgs.join(',') // ["name", "age"]===> name, age
}
head() {
return `"use strict";var _context;var _x = this._x;`
}
content() {
let code = `var _counter = ${this.options.taps.length};var _done = (function () {
_callback();
});`
for (var i = 0; i < this.options.taps.length; i++) {
code += `var _fn${i} = _x[${i}];_fn${i}(name, age, (function () {
if (--_counter === 0) _done();
}));`
}
return code
}
setup(instance, options) { // 先准备后续需要使用到的数据
this.options = options // 这里的操作在源码中是通过 init 方法实现,而我们当前是直接挂在了 this 身上
instance._x = options.taps.map(o => o.fn) // this._x = [f1, f2, ....]
}
create() { // 核心就是创建一段可执行的代码体然后返回
let fn
// fn = new Function("name, age", "var _x = this._x, var _fn0 = _x[0]; _fn0(name, age);")
fn = new Function(
this.args({ after: '_callback' }),
this.head() + this.content()
)
return fn
}
}
let factory = new HookCodeFactory()
class AsyncParallelHook extends Hook {
constructor(args) {
super(args)
}
compile(options) { // {taps: [{}, {}], args: [name, age]}
factory.setup(this, options)
return factory.create(options)
}
}
module.exports = AsyncParallelHook