[webpack]深入学习webpack核心模块tapable
一、手动实现同步钩子函数
1、SyncHook
class SyncHook {
// 钩子是同步的
constructor(args){
this.tasks = [];
}
tap(name,task){
this.tasks.push(task)
}
call(...args){
this.tasks.forEach(
(task)=>task(...args)
)
}
}
// 绑定事件就是订阅
let hook = new SyncHook(['name']);
hook.tap('react',function (name) {
console.log('react',name)
});
hook.tap('node',function (name) {
console.log('node',name)
});
hook.call('dellyoung');
2、SyncWaterfallHook
class SyncWaterfallHook {
// 钩子是同步的
constructor(args){
this.tasks = [];
}
tap(name,task){
this.tasks.push(task)
}
call(...args){
let [first,...others] = this.tasks;
let ret = first(...args);
others.reduce(
(a,b)=>{
// a 上一个 b 下一个
return b(a);
},ret
)
}
}
// 绑定事件就是订阅
let hook = new SyncWaterfallHook(['name']);
hook.tap('react',function (name) {
console.log('react1',name);
return 'reactOk'
});
hook.tap('node',function (name) {
console.log('node2',name);
return 'nodeOk'
});
hook.tap('webpack',function (name) {
console.log('webpack',name)
});
hook.call('dellyoung');
3、SyncLoopHook
class SyncLoopHook {
// 钩子是同步的
// 只要返回不是undefined就会一直循环
constructor(args){
this.tasks = [];
}
tap(name,task){
this.tasks.push(task)
}
call(...args){
this.tasks.forEach(
task=>{
let ret;
do {
ret = task(...args)
}while (ret !== undefined)
}
)
}
}
// 绑定事件就是订阅
let hook = new SyncLoopHook(['name']);
let total = 0;
hook.tap('react',function (name) {
console.log('react',name);
return ++total === 3?undefined:'继续学'
});
hook.tap('node',function (name) {
console.log('node',name);
});
hook.tap('webpack',function (name) {
console.log('webpack',name)
});
hook.call('dellyoung');
4、SyncBailHook
class SyncBailHook {
// 钩子是同步的
constructor(args){
this.tasks = [];
}
tap(name,task){
this.tasks.push(task)
}
call(...args){
let ret; // 当前函数返回值
let index=0; // 先执行第一个
do{
ret = this.tasks[index++](...args)
}while (ret === undefined && index < this.tasks.length);
}
}
// 绑定事件就是订阅
let hook = new SyncBailHook(['name']);
hook.tap('react',function (name) {
console.log('react1',name);
// return '停止'
});
hook.tap('node',function (name) {
console.log('node2',name)
});
hook.call('dellyoung');
二、手动实现异步钩子函数
1、AsyncParallelBailHook
类似promise.all[]
class AsyncParallelBailHook {
// 钩子是同步的
// 只要返回不是undefined就会一直循环
constructor(args){
this.tasks = [];
}
tapAsync(name,task){
this.tasks.push(task)
}
callAsync(...args){
let finalCallBack = args.pop(); // 拿出最终的函数
let index = 0;
let done = () => {
index++;
if(index === this.tasks.length){
finalCallBack();
}
};
this.tasks.forEach(task=>{
task(...args,done)
})
}
}
// 绑定事件就是订阅
let hook = new AsyncParallelBailHook(['name']);
hook.tapAsync('react',function (name,callback) {
setTimeout(()=>{
console.log('react',name);
callback();
},5000
);
});
hook.tapAsync('node',function (name,callback) {
setTimeout(()=>{
console.log('node',name);
callback();
},1000
);
});
hook.callAsync('dellyoung',function () {
console.log('newBegin')
});
promise版本的AsyncParallelBailHook
class AsyncParallelBailHook { // 钩子是同步的 // 只要返回不是undefined就会一直循环 constructor(args) { this.tasks = []; } tabPromise(name, task) { this.tasks.push(task) } promise(...args) { let tasks = this.tasks.map( (task) => { return task(...args) } ); // let tasks = this.tasks.map(task => task(...args)); return Promise.all(tasks); } } // 绑定事件就是订阅 let hook = new AsyncParallelBailHook(['name']); hook.tabPromise('react', function (name) { return new Promise( (resolve, reject) => { setTimeout(() => { console.log('react', name); resolve(); }, 1000 ); } ) }); hook.tabPromise('node', function (name) { return new Promise( (resolve, reject) => { setTimeout(() => { console.log('node', name); resolve(); }, 2000 ); } ) }); hook.promise('dellyoung').then(function () { console.log('newBegin') });
2、AsyncSeriesHook
异步串行
class AsyncSeriesHook { constructor(args) { this.tasks = []; } tabAsync(name, task) { this.tasks.push(task) } callAsync(...args) { let finalCallBack = args.pop(); let index = 0; let next = () => { if(this.tasks.length === index){ return finalCallBack(); } let task = this.tasks[index++]; task(...args, next); }; next(); } } // 绑定事件就是订阅 let hook = new AsyncSeriesHook(['name']); hook.tabAsync('react', function (name, callback) { setTimeout(() => { console.log('react', name); callback(); }, 3000 ); }); hook.tabAsync('node', function (name, callback) { setTimeout(() => { console.log('node', name); callback(); }, 1000 ) }); hook.callAsync('dellyoung',function () { console.log('newBegin') });
promise版本的AsyncSeriesHook
class AsyncSeriesHook { constructor(args) { this.tasks = []; } tabPromise(name, task) { this.tasks.push(task) } promise(...args) { // 类redux源码 let [first,...other] = this.tasks; return other.reduce( (prom,n)=>{ return prom.then(()=>n(...args)) },first(...args) ) } } // 绑定事件就是订阅 let hook = new AsyncSeriesHook(['name']); hook.tabPromise('react', function (name) { return new Promise( (resolve, reject) => { setTimeout(() => { console.log('react', name); resolve(); }, 1000 ); } ) }); hook.tabPromise('node', function (name) { return new Promise( (resolve, reject) => { setTimeout(() => { console.log('node', name); resolve(); }, 1000 ); } ) }); hook.promise('dellyoung').then(function () { console.log('newBegin') });
3、AsyncSeriesWaterfallHook
异步瀑布串行
class AsyncSeriesWaterfallHook { constructor(args) { this.tasks = []; } tapAsync(name, task) { this.tasks.push(task) } callAsync(...args) { let finalCb = args.pop(); let index = 0; let next = (err,data) => { let task = this.tasks[index]; if(!task) return finalCb(); if(err) return ; if(index===0){ // 执行第一个 task(...args,next) }else { task(data,next) } index++; }; next() } } // 绑定事件就是订阅 let hook = new AsyncSeriesWaterfallHook(['name']); hook.tapAsync('react', function (name, cb) { setTimeout(() => { console.log('react', name); cb(null, 'result1'); }, 1000 ); }); hook.tapAsync('node', function (data, cb) { setTimeout(() => { console.log('node', data); cb(null); }, 2000 ); }); hook.callAsync('dellyoung',function () { console.log('newBegin') });