最近学了学webpack的插件,其实挺简单的,webpack本质上是一种事件流机制,核心是tapable(不是table),通过事件的注册和监听,触发函数方法。所以写插件就是通过暴露给我们的方法去注册和调用。
tapable主要是同步和异步,异步分为并行和串行,今天主要是学习一下异步的并行和串行,才能更好理解tapable。现在实现异步的有很多,比如promise、generator、async await,用这些去实现异步的并行和串行非常简便,promise的all方法就是异步的并行。
异步并行:
我觉得应该不需要解释,就是几个异步同时执行,最后一个执行完毕调用一下回调方法,简单实现:
class AsyncParallel{
constructor() {
this.cbList = [];
}
tap(fn) {
this.cbList.push(fn);
}
call(end){
let index = 0;
this.cbList.forEach(fn => {
fn(() => {
index++;
if(index === this.cbList.length){end()};
});
})
}
}
let ap = new AsyncParallel();
ap.tap((cb) => {
setTimeout(() => {
console.log(1);
cb();
}, 3000)
})
ap.tap((cb) => {
setTimeout(() => {
console.log(3);
cb();
}, 1000)
});
ap.call(() => {
console.log('end');
})
异步串行:
第一个执行完执行下一个,其实就是用一个next方法去判断执行下一个,简单实现:
class AsyncSerial{
constructor() {
this.cbList = [];
}
tap(fn) {
this.cbList.push(fn);
}
call(end){
let index = 0;
let next = () => {
if(index === this.cbList.length){
end();
return;
}
let fn = this.cbList[index];
fn(() => {
index++;
next();
})
}
next();
}
}
let ap = new AsyncSerial();
ap.tap((cb) => {
setTimeout(() => {
console.log(1);
cb();
}, 3000)
})
ap.tap((cb) => {
setTimeout(() => {
console.log(3);
cb();
}, 2000)
});
ap.call(() => {
console.log('end');
})
大概就是这样,继续扩展就会复杂很多,比如是否要把结果传递下去,中间报错是否就终止,返回值如果不是undefined是否继续等,如果使用promise会更简单一些。然后建议去看看tapable,里面可以实现的会更多跟复杂,如果想学习webpack内部一些机制,tapable是一定要了解的。