const {
SyncHook,
SyncBailHook,
SyncWaterfallHook,
SyncLoopHook,
AsyncParallelHook,
AsyncParallelBailHook,
AsyncSeriesHook,
AsyncSeriesBailHook,
AsyncSeriesWaterfallHook
} = require('tapable');
同步Sync
和异步Async
,异步又分为并行
和串行
result !== undefined
则返回,不再继续执行。有:SyncBailHook、AsyncSeriesBailHook, AsyncParallelBailHookresult !== undefined
,则 result 会作为后一个事件函数的第一个参数,有SyncWaterfallHook,AsyncSeriesWaterfallHookresult === undefined
,有SyncLoopHook 和 AsyncSeriesLoopHook const {SyncHook} = require('tapable');
const hook = new SyncHook(['name','age']);
hook.tap('1',(name,age)=>{
console.log(1,name,age);
return 1;
});
hook.tap('2',(name,age)=>{
console.log(2,name,age);
return 2;
});
hook.tap('3',(name,age)=>{
console.log(3,name,age);
return 3;
});
hook.call('zhufeng',10);
1 zhufeng 10
2 zhufeng 10
3 zhufeng 10
const {SyncBailHook} = require('tapable');
const hook = new SyncBailHook(['name','age']);
hook.tap('1',(name,age)=>{
console.log(1,name,age);
//return 1;
});
hook.tap('2',(name,age)=>{
console.log(2,name,age);
return 2;
});
hook.tap('3',(name,age)=>{
console.log(3,name,age);
return 3;
});
hook.call('zhufeng',10);
const {SyncWaterfallHook} = require('tapable');
const hook = new SyncWaterfallHook(['name','age']);
hook.tap('1',(name,age)=>{
console.log(1,name,age);
return 1;
});
hook.tap('2',(name,age)=>{
console.log(2,name,age);
return ;
});
hook.tap('3',(name,age)=>{
console.log(3,name,age);
return 3;
});
hook.call('zhufeng',10);
const { SyncLoopHook } = require('tapable');
//当回调函数返回非undefined值的时候会停止调用后续的回调
let hook = new SyncLoopHook(['name', 'age']);
let counter1 = 0;
let counter2 = 0;
let counter3 = 0;
hook.tap('1', (name, age) => {
console.log(1, 'counter1', counter1);
if (++counter1 == 1) {
counter1 = 0
return;
}
return true;
});
hook.tap('2', (name, age) => {
console.log(2, 'counter2', counter2);
if (++counter2 == 2) {
counter2 = 0
return;
}
return true;
});
hook.tap('3', (name, age) => {
console.log(3, 'counter3', counter3);
if (++counter3 == 3) {
counter3 = 0
return;
}
return true;
});
hook.call('zhufeng', 10);
1 counter1 0
2 counter2 0
1 counter1 0
2 counter2 1
3 counter3 0
1 counter1 0
2 counter2 0
1 counter1 0
2 counter2 1
3 counter3 1
1 counter1 0
2 counter2 0
1 counter1 0
2 counter2 1
3 counter3 2
let {AsyncParallelHook}=require('tapable');
let queue = new AsyncParallelHook(['name']);
console.time('cost');
queue.tap('1',function(name){
console.log(1);
});
queue.tap('2',function(name){
console.log(2);
});
queue.tap('3',function(name){
console.log(3);
});
queue.callAsync('zfpx',err=>{
console.log(err);
console.timeEnd('cost');
});
let {AsyncParallelHook}=require('tapable');
let queue = new AsyncParallelHook(['name']);
console.time('cost');
queue.tapAsync('1',function(name,callback){
setTimeout(function(){
console.log(1);
callback();
},1000)
});
queue.tapAsync('2',function(name,callback){
setTimeout(function(){
console.log(2);
callback();
},2000)
});
queue.tapAsync('3',function(name,callback){
setTimeout(function(){
console.log(3);
callback();
},3000)
});
queue.callAsync('zfpx',err=>{
console.log(err);
console.timeEnd('cost');
});
let {AsyncParallelHook}=require('tapable');
let queue = new AsyncParallelHook(['name']);
console.time('cost');
queue.tapPromise('1',function(name){
return new Promise(function(resolve,reject){
setTimeout(function(){
console.log(1);
resolve();
},1000)
});
});
queue.tapPromise('2',function(name){
return new Promise(function(resolve,reject){
setTimeout(function(){
console.log(2);
resolve();
},2000)
});
});
queue.tapPromise('3',function(name){
return new Promise(function(resolve,reject){
setTimeout(function(){
console.log(3);
resolve();
},3000)
});
});
queue.promise('zfpx').then(()=>{
console.timeEnd('cost');
})
let {AsyncParallelBailHook} = require('tapable');
let queue=new AsyncParallelBailHook(['name']);
console.time('cost');
queue.tap('1',function(name){
console.log(1);
return "Wrong";
});
queue.tap('2',function(name){
console.log(2);
});
queue.tap('3',function(name){
console.log(3);
});
queue.callAsync('zfpx',err=>{
console.log(err);
console.timeEnd('cost');
});
let {AsyncParallelBailHook} = require('tapable');
let queue=new AsyncParallelBailHook(['name']);
console.time('cost');
queue.tapAsync('1',function(name,callback){
console.log(1);
callback('Wrong');
});
queue.tapAsync('2',function(name,callback){
console.log(2);
callback();
});
queue.tapAsync('3',function(name,callback){
console.log(3);
callback();
});
queue.callAsync('zfpx',err=>{
console.log(err);
console.timeEnd('cost');
});
let { AsyncParallelBailHook } = require('tapable');
let queue = new AsyncParallelBailHook(['name']);
console.time('cost');
queue.tapPromise('1', function (name) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log(1);
resolve(1);
}, 1000)
});
});
queue.tapPromise('2', function (name) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log(2);
resolve();
}, 2000)
});
});
queue.tapPromise('3', function (name) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log(3);
resolve();
}, 3000)
});
});
queue.promise('zfpx').then((result) => {
console.log('成功', result);
console.timeEnd('cost');
}, err => {
console.error('失败', err);
console.timeEnd('cost');
})
let { AsyncSeriesHook } = require('tapable');
let queue = new AsyncSeriesHook(['name']);
console.time('cost');
queue.tap('1', function (name) {
console.log(1);
});
queue.tap('2', function (name) {
console.log(2);
});
queue.tap('3', function (name) {
console.log(3);
});
queue.callAsync('zhufeng', err => {
console.log(err);
console.timeEnd('cost');
});
let { AsyncSeriesHook } = require('tapable');
let queue = new AsyncSeriesHook(['name']);
console.time('cost');
queue.tapAsync('1',function(name,callback){
setTimeout(function(){
console.log(1);
},1000)
});
queue.tapAsync('2',function(name,callback){
setTimeout(function(){
console.log(2);
callback();
},2000)
});
queue.tapAsync('3',function(name,callback){
setTimeout(function(){
console.log(3);
callback();
},3000)
});
queue.callAsync('zfpx',err=>{
console.log(err);
console.timeEnd('cost');
});
let { AsyncSeriesHook } = require('tapable');
let queue = new AsyncSeriesHook(['name']);
console.time('cost');
queue.tapPromise('1', function (name) {
return new Promise(function (resolve) {
setTimeout(function () {
console.log(1, name);
resolve();
}, 1000)
});
});
queue.tapPromise('2', function (name) {
return new Promise(function (resolve) {
setTimeout(function () {
console.log(2, name);
resolve();
}, 2000)
});
});
queue.tapPromise('3', function (name) {
return new Promise(function (resolve) {
setTimeout(function () {
console.log(3, name);
resolve();
}, 3000)
});
});
queue.promise('zfpx').then(data => {
console.log(data);
console.timeEnd('cost');
});
let {AsyncSeriesBailHook} = require('tapable');
let queue = new AsyncSeriesBailHook(['name']);
console.time('cost');
queue.tap('1',function(name){
console.log(1);
return "Wrong";
});
queue.tap('2',function(name){
console.log(2);
});
queue.tap('3',function(name){
console.log(3);
});
queue.callAsync('zfpx',err=>{
console.log(err);
console.timeEnd('cost');
});
let {AsyncSeriesBailHook}=require('tapable');
let queue = new AsyncSeriesBailHook(['name']);
console.time('cost');
queue.tapAsync('1',function(name,callback){
setTimeout(function(){
console.log(1);
callback('wrong');
},1000)
});
queue.tapAsync('2',function(name,callback){
setTimeout(function(){
console.log(2);
callback();
},2000)
});
queue.tapAsync('3',function(name,callback){
setTimeout(function(){
console.log(3);
callback();
},3000)
});
queue.callAsync('zfpx',err=>{
console.log(err);
console.timeEnd('cost');
});
let {AsyncSeriesBailHook} = require('tapable');
let queue = new AsyncSeriesBailHook(['name']);
console.time('cost');
queue.tapPromise('1',function(name){
return new Promise(function(resolve){
setTimeout(function(){
console.log(1);
resolve();
},1000)
});
});
queue.tapPromise('2',function(name,callback){
return new Promise(function(resolve,reject){
setTimeout(function(){
console.log(2);
reject('失败了');
},2000)
});
});
queue.tapPromise('3',function(name,callback){
return new Promise(function(resolve){
setTimeout(function(){
console.log(3);
resolve();
},3000)
});
});
queue.promise('zfpx').then(data=>{
console.log(data);
console.timeEnd('cost');
},error=>{
console.log(error);
console.timeEnd('cost');
});
let { AsyncSeriesWaterfallHook } = require('tapable');
let queue = new AsyncSeriesWaterfallHook(['name', 'age']);
console.time('cost');
queue.tap('1', function (name, age) {
console.log(1, name, age);
return 'return1';
});
queue.tap('2', function (data, age) {
console.log(2, data, age);
return 'return2';
});
queue.tap('3', function (data, age) {
console.log(3, data, age);
});
queue.callAsync('zfpx', 10, err => {
console.log(err);
console.timeEnd('cost');
});
let { AsyncSeriesWaterfallHook } = require('tapable');
let queue = new AsyncSeriesWaterfallHook(['name', 'age']);
console.time('cost');
queue.tapAsync('1', function (name, age, callback) {
setTimeout(function () {
console.log(1, name, age);
callback(null, 1);
}, 1000)
});
queue.tapAsync('2', function (data, age, callback) {
setTimeout(function () {
console.log(2, data, age);
callback(null, 2);
}, 2000)
});
queue.tapAsync('3', function (data, age, callback) {
setTimeout(function () {
console.log(3, data, age);
callback(null, 3);
}, 3000)
});
queue.callAsync('zfpx', 10, (err, data) => {
console.log(err, data);
console.timeEnd('cost');
});
let {AsyncSeriesWaterfallHook} = require('tapable');
let queue = new AsyncSeriesWaterfallHook(['name']);
console.time('cost');
queue.tapPromise('1', function (name) {
return new Promise(function (resolve) {
setTimeout(function () {
console.log(name, 1);
resolve(1);
}, 1000);
});
});
queue.tapPromise('2', function (data) {
return new Promise(function (resolve) {
setTimeout(function () {
console.log(data, 2);
resolve(2);
}, 2000);
});
});
queue.tapPromise('3', function (data) {
return new Promise(function (resolve) {
setTimeout(function () {
console.log(data, 3);
resolve(3);
}, 3000);
});
});
queue.promise('zfpx').then(err => {
console.timeEnd('cost');
});
//const { SyncHook } = require("./tapable");
const { SyncHook } = require('tapable');
let syncHook = new SyncHook(["name", "age"]);
syncHook.tap("1", (name, age) => {
console.log(1, name, age);
});
syncHook.tap("2", (name, age) => {
console.log(2, name, age);
});
syncHook.call("zhufeng", 10);
(function anonymous(name, age
) {
"use strict";
var _context;
var _x = this._x;
var _fn0 = _x[0];
_fn0(name, age);
var _fn1 = _x[1];
_fn1(name, age);
})
tapable\index.js
let SyncHook = require('./SyncHook');
module.exports = {
SyncHook
}
tapable\Hook.js
class Hook {
constructor(args) {
if (!Array.isArray(args)) args = []; //参数
this.args = args; // 这里存入初始化的参数
this.taps = []; //这里就是回调栈用到的数组
this._x = undefined; //这个比较重要,后面拼代码会用
}
tap(options, fn) {
if (typeof options === "string") options = { name: options };
options.fn = fn;
this._insert(options); //参数处理完之后,调用_insert,这是关键代码
}
_insert(item) {
this.taps[this.taps.length] = item;
}
call(...args) {
let callMethod = this._createCall();
return callMethod.apply(this, args);
}
_createCall() {
return this.compile({
taps: this.taps,
args: this.args
});
}
}
module.exports = Hook;
tapable\SyncHook.js
const Hook = require("./Hook");
const HookCodeFactory = require("./HookCodeFactory");
const factory = new HookCodeFactory();
class SyncHook extends Hook {
constructor(args) {
super(args);
}
compile(options) {
factory.setup(this, options);
return factory.create(options);
}
}
module.exports = SyncHook;
tapable\HookCodeFactory.js
class HookCodeFactory {
args() {
return this.options.args.join(",");
}
setup(instance, options) {
this.options = options;
instance._x = options.taps.map(t => t.fn);
}
header() {
return "var _x = this._x;\n";
}
content() {
let code = "";
for (let idx = 0; idx < this.options.taps.length; idx++) {
code += `var _fn${idx} = _x[${idx}];\n
_fn${idx}(${this.args()});\n`;
}
return code;
}
create() {
return new Function(this.args(), this.header() + this.content());
}
}
module.exports = HookCodeFactory;
let { AsyncParallelHook } = require('./tapable');
let queue = new AsyncParallelHook(['name', 'age']);
console.time('cost');
queue.tapAsync('1', function (name, age, callback) {
setTimeout(function () {
console.log(1, name, age);
callback();
}, 1000)
});
queue.tapAsync('2', function (name, age, callback) {
setTimeout(function () {
console.log(2, name, age);
callback();
}, 2000)
});
queue.tapAsync('3', function (name, age, callback) {
setTimeout(function () {
console.log(3, name, age);
callback();
}, 3000)
});
queue.callAsync('zhufeng', 10, err => {
console.timeEnd('cost');
});
(function anonymous(name, age, _callback
) {
"use strict";
var _x = this._x;
do {
var _counter = 3;
var _done = () => {
_callback();
};
if (_counter <= 0) break;
var _fn0 = _x[0];
_fn0(name, age, _err0 => {
if (_err0) {
if (_counter > 0) {
_callback(_err0);
_counter = 0;
}
} else {
if (--_counter === 0) _done();
}
});
if (_counter <= 0) break;
var _fn1 = _x[1];
_fn1(name, age, _err1 => {
if (_err1) {
if (_counter > 0) {
_callback(_err1);
_counter = 0;
}
} else {
if (--_counter === 0) _done();
}
});
if (_counter <= 0) break;
var _fn2 = _x[2];
_fn2(name, age, _err2 => {
if (_err2) {
if (_counter > 0) {
_callback(_err2);
_counter = 0;
}
} else {
if (--_counter === 0) _done();
}
});
} while (false);
})
tapable\index.js
let SyncHook = require('./SyncHook');
+let AsyncParallelHook = require('./AsyncParallelHook');
module.exports = {
SyncHook,
+ AsyncParallelHook
}
AsyncParallelHookCodeFactory.js
const HookCodeFactory = require("./HookCodeFactory");
class AsyncParallelHookCodeFactory extends HookCodeFactory {
args({ before, after } = {}) {
let allArgs = this.options.args || [];
if (before) allArgs = [before, ...allArgs];
if (after) allArgs = [...allArgs, after];
if (allArgs.length === 0) {
return "";
} else {
return allArgs.join(",");
}
}
create() {
return new Function(
this.args({ after: "_callback" }),
this.header() + this.content()
);
}
content() {
let code = ``;
code += `
var _counter = ${this.options.taps.length};
var _done = () =>{
_callback();
};
`;
for (let idx = 0; idx < this.options.taps.length; idx++) {
code += `
var _fn${idx} = _x[${idx}];
_fn${idx}(${this.args()}, _err${idx} =>{
if (--_counter === 0) _done();
});
`;
}
return code;
}
}
module.exports = AsyncParallelHookCodeFactory;
AsyncParallelHook.js
const Hook = require("./Hook");
let AsyncParallelHookCodeFactory = require('./AsyncParallelHookCodeFactory');
const factory = new AsyncParallelHookCodeFactory();
class AsyncParallelHook extends Hook {
constructor(args) {
super(args);
}
tapAsync(options, fn) {
if (typeof options === "string") options = { name: options };
options.fn = fn;
this._insert(options);
}
callAsync(...args) {
let callMethod = this._createCall();
return callMethod.apply(this, args);
}
compile(options) {
factory.setup(this, options);
return factory.create(options);
}
}
module.exports = AsyncParallelHook;
let { AsyncParallelHook } = require('tapable');
let queue = new AsyncParallelHook(['name', 'age']);
console.time('cost');
queue.tapPromise('1', function (name, age) {
return new Promise(function (resolve) {
setTimeout(function () {
console.log(1, name, age);
resolve();
}, 1000)
});
});
queue.tapPromise('2', function (name, age) {
return new Promise(function (resolve) {
setTimeout(function () {
console.log(2, name, age);
resolve();
}, 2000)
});
});
queue.tapPromise('3', function (name, age) {
return new Promise(function (resolve) {
setTimeout(function () {
console.log(3, name, age);
resolve();
}, 3000)
});
});
queue.promise('zhufeng', 10).then(result => {
console.timeEnd('cost');
}, error => {
console.log(error);
console.timeEnd('cost');
});
(function anonymous(name, age
) {
"use strict";
return new Promise((_resolve, _reject) => {
var _sync = true;
function _error(_err) {
if (_sync)
_resolve(Promise.resolve().then(() => { throw _err; }));
else
_reject(_err);
};
var _x = this._x;
do {
var _counter = 3;
var _done = () => {
_resolve();
};
if (_counter <= 0) break;
var _fn0 = _x[0];
var _hasResult0 = false;
var _promise0 = _fn0(name, age);
if (!_promise0 || !_promise0.then)
throw new Error('Tap function (tapPromise) did not return promise (returned ' + _promise0 + ')');
_promise0.then(_result0 => {
_hasResult0 = true;
if (--_counter === 0) _done();
}, _err0 => {
if (_hasResult0) throw _err0;
if (_counter > 0) {
_error(_err0);
_counter = 0;
}
});
if (_counter <= 0) break;
var _fn1 = _x[1];
var _hasResult1 = false;
var _promise1 = _fn1(name, age);
if (!_promise1 || !_promise1.then)
throw new Error('Tap function (tapPromise) did not return promise (returned ' + _promise1 + ')');
_promise1.then(_result1 => {
_hasResult1 = true;
if (--_counter === 0) _done();
}, _err1 => {
if (_hasResult1) throw _err1;
if (_counter > 0) {
_error(_err1);
_counter = 0;
}
});
if (_counter <= 0) break;
var _fn2 = _x[2];
var _hasResult2 = false;
var _promise2 = _fn2(name, age);
if (!_promise2 || !_promise2.then)
throw new Error('Tap function (tapPromise) did not return promise (returned ' + _promise2 + ')');
_promise2.then(_result2 => {
_hasResult2 = true;
if (--_counter === 0) _done();
}, _err2 => {
if (_hasResult2) throw _err2;
if (_counter > 0) {
_error(_err2);
_counter = 0;
}
});
} while (false);
_sync = false;
});
})
tapable\index.js
let SyncHook = require('./SyncHook');
let AsyncParallelHook = require('./AsyncParallelHook');
+let AsyncParallelHookForPromise = require('./AsyncParallelHookForPromise');
module.exports = {
SyncHook,
AsyncParallelHook,
+ AsyncParallelHookForPromise
}
doc\tapable\AsyncParallelHookCodeFactoryForPromise.js
const HookCodeFactory = require("./HookCodeFactory");
class AsyncParallelHookCodeFactory extends HookCodeFactory {
args({ before, after } = {}) {
let allArgs = this.options.args || [];
if (before) allArgs = [before, ...allArgs];
if (after) allArgs = [...allArgs, after];
if (allArgs.length === 0) {
return "";
} else {
return allArgs.join(",");
}
}
create() {
return new Function(this.args(), this.header() + this.content());
}
content() {
let code = ``;
code += `
return new Promise((_resolve)=>{
var _counter = ${this.options.taps.length};
var _done = ()=>{
_resolve();
};
`;
for (let idx = 0; idx < this.options.taps.length; idx++) {
code += `
var _fn${idx} = _x[${idx}];
var _promise${idx} = _fn${idx}(${this.args()});
_promise${idx}.then(_result${idx} =>{
if (--_counter === 0) _done();
});
`;
}
code += `
});
`;
return code;
}
}
module.exports = AsyncParallelHookCodeFactory;
AsyncParallelHookForPromise.js
let AsyncParallelHookCodeFactoryForPromise = require('./AsyncParallelHookCodeFactoryForPromise');
let Hook = require('./Hook');
const factory = new AsyncParallelHookCodeFactoryForPromise();
class AsyncParallelHookForPromise extends Hook {
constructor(args) {
super(args);
}
tapPromise(options, fn) {
if (typeof options === "string") options = { name: options };
options.fn = fn;
this._insert(options);
}
promise(...args) {
let callMethod = this._createCall();
return callMethod.apply(this, args);
}
compile(options) {
factory.setup(this, options);
return factory.create(options);
}
}
module.exports = AsyncParallelHookForPromise;