接上一篇文章 深切明白Webpack中心模块WTApable钩子(同步版)
tapable中三个注册要领
- 1 tap(同步) 2 tapAsync(cb) 3 tapPromise(注册的是Promise)
tapable中对三个触发要领
- 1 call 2 callAsync 3 promise
这一章节 我们将离别完成异步的Async版本和Promise版本
异步钩子
- AsyncParallelHook
- AsyncParallelHook的Promise版本
- AsyncSeriesHook
- AsyncSeriesHook的Promise版本
- AsyncSeriesWaterfallHook
- AsyncSeriesWaterfallHook的Promise版本
异步的钩子分为并行和串行的钩子,并行是指 守候一切并发的异步事宜实行以后再实行终究的异步回调。
而串行是值 第一步实行终了再去实行第二步,以此类推,直到实行完一切回调再去实行终究的异步回调。
AsyncParallelHook
AsyncParallelHook是异步并行的钩子,上代码:
const { AsyncParallelHook } = require('tapable');
class Hook{
constructor(){
this.hooks = new AsyncParallelHook(['name']);
}
tap(){
/** 异步的注册要领是tapAsync()
* 而且有回调函数cb.
*/
this.hooks.tapAsync('node',function(name,cb){
setTimeout(()=>{
console.log('node',name);
cb();
},1000);
});
this.hooks.tapAsync('react',function(name,cb){
setTimeout(()=>{
console.log('react',name);
cb();
},1000);
});
}
start(){
/** 异步的触发要领是callAsync()
* 多了一个终究的回调函数 fn.
*/
this.hooks.callAsync('call end.',function(){
console.log('终究的回调');
});
}
}
let h = new Hook();
h.tap();/** 相似定阅 */
h.start();/** 相似宣布 */
/* 打印递次:
node call end.
react call end.
终究的回调
*/
守候1s后,离别实行了node call end和react callend 末了实行了终究的回调fn.
手动完成:
class AsyncParallelHook{
constructor(args){ /* args -> ['name']) */
this.tasks = [];
}
/** tap吸收两个参数 name和fn */
tap(name,fn){
/** 定阅:将fn放入到this.tasks中 */
this.tasks.push(fn);
}
start(...args){
let index = 0;
/** 经由过程pop()猎取到末了一个参数
* finalCallBack() 终究的回调
*/
let finalCallBack = args.pop();
/** 箭头函数绑定this */
let done = () => {
/** 实行done() 每次index+1 */
index++;
if(index === this.tasks.length){
/** 实行终究的回调 */
finalCallBack();
}
}
this.tasks.forEach((task)=>{
/** 实行每一个task,传入我们给定的done回调函数 */
task(...args,done);
});
}
}
let h = new AsyncParallelHook(['name']);
/** 定阅 */
h.tap('react',(name,cb)=>{
setTimeout(()=>{
console.log('react',name);
cb();
},1000);
});
h.tap('node',(name,cb)=>{
setTimeout(()=>{
console.log('node',name);
cb();
},1000);
});
/** 宣布 */
h.start('end.',function(){
console.log('终究的回调函数');
});
/* 打印递次:
react end.
node end.
终究的回调函数
*/
AsyncParallelHook的Promise版本
const { AsyncParallelHook } = require('tapable');
class Hook{
constructor(){
this.hooks = new AsyncParallelHook(['name']);
}
tap(){
/** 这里是Promsie写法
* 注册事宜的要领为tapPromise
*/
this.hooks.tapPromise('node',function(name){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('node',name);
resolve();
},1000);
});
});
this.hooks.tapPromise('react',function(name){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('react',name);
resolve();
},1000);
});
});
}
start(){
/**
* promsie终究返回一个prosise 胜利resolve时
* .then即为终究回调
*/
this.hooks.promise('call end.').then(function(){
console.log('终究的回调');
});
}
}
let h = new Hook();
h.tap();
h.start();
/* 打印递次:
node call end.
react call end.
终究的回调
*/
这里钩子照样AsyncParallelHook钩子,只是写法变成了promise的写法,去掉了回调函数cb().变成了胜利时去resolve().其有用Promise能够更好处理异步并行的题目,由于Promise的原型要领上有个all()要领,它的作用就是守候一切promise实行终了后再去实行终究的promise。我们如今去完成它:
class SyncHook{
constructor(args){
this.tasks = [];
}
tapPromise(name,fn){
this.tasks.push(fn);
}
promise(...args){
/** 应用map要领返回一个新数组的特征 */
let tasks = this.tasks.map((task)=>{
/** 每一个task都是一个Promise */
return task(...args);
});
/** Promise.all() 守候一切Promise都实行终了 */
return Promise.all(tasks);
}
}
let h = new SyncHook(['name']);
/** 定阅 */
h.tapPromise('react',(name)=>{
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('react',name);
resolve();
},1000);
});
});
h.tapPromise('node',(name)=>{
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('node',name);
resolve();
},1000);
});
});
/** 宣布 */
h.promise('end.').then(function(){
console.log('终究的回调函数');
});
/* 打印递次:
react end.
node end.
终究的回调函数
*/
AsyncSeriesHook
AsyncSeriesHook是异步串行的钩子, 串行,我们适才说了, 它是一步步去实行的,下一步实行依靠上一步实行是不是完成,手动完成:
const { AsyncSeriesHook } = require('tapable');
class Hook{
constructor(){
this.hooks = new AsyncSeriesHook(['name']);
}
tap(){
/** 异步的注册要领是tapAsync()
* 而且有回调函数cb.
*/
this.hooks.tapAsync('node',function(name,cb){
setTimeout(()=>{
console.log('node',name);
cb();
},1000);
});
this.hooks.tapAsync('react',function(name,cb){
/** 此回调要守候上一个回调实行终了后才最先实行 */
setTimeout(()=>{
console.log('react',name);
cb();
},1000);
});
}
start(){
/** 异步的触发要领是callAsync()
* 多了一个终究的回调函数 fn.
*/
this.hooks.callAsync('call end.',function(){
console.log('终究的回调');
});
}
}
let h = new Hook();
h.tap();
h.start();
/* 打印递次:
node call end.
react call end. -> 1s后打印
终究的回调 -> 1s后打印
*/
AsyncParallelHook和AsyncSeriesHook的区别是AsyncSeriesHook是串行的异步钩子,也就是说它会守候上一步的实行 只要上一步实行终了了 才会最先实行下一步。而AsyncParallelHook是并行异步 AsyncParallelHook 是同时并发实行。 ok.手动完成 AsyncSeriesHook:
class AsyncParallelHook{
constructor(args){ /* args -> ['name']) */
this.tasks = [];
}
/** tap吸收两个参数 name和fn */
tap(name,fn){
/** 定阅:将fn放入到this.tasks中 */
this.tasks.push(fn);
}
start(...args){
let index = 0;
let finalCallBack = args.pop();
/** 递归实行next()要领 直到实行一切task
* 末了实行终究的回调finalCallBack()
*/
let next = () => {
/** 直到实行完一切task后
* 再实行终究的回调 finalCallBack()
*/
if(index === this.tasks.length){
return finalCallBack();
}
/** index++ 实行每一个task 并传入递归函数next
* 实行完每一个task后继承递归实行下一个task
* next === cb,next就是每一步的cb回调
*/
this.tasks[index++](...args,next);
}
/** 实行next() */
next();
}
}
let h = new AsyncParallelHook(['name']);
/** 定阅 */
h.tap('react',(name,cb)=>{
setTimeout(()=>{
console.log('react',name);
cb();
},1000);
});
h.tap('node',(name,cb)=>{
setTimeout(()=>{
console.log('node',name);
cb();
},1000);
});
/** 宣布 */
h.start('end.',function(){
console.log('终究的回调函数');
});
/* 打印递次:
react end.
node end. -> 1s后打印
终究的回调函数 -> 1s后打印
*/
AsyncSeriesHook的Promise版本
const { AsyncSeriesHook } = require('tapable');
class Hook{
constructor(){
this.hooks = new AsyncSeriesHook(['name']);
}
tap(){
/** 这里是Promsie写法
* 注册事宜的要领为tapPromise
*/
this.hooks.tapPromise('node',function(name){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('node',name);
resolve();
},1000);
});
});
this.hooks.tapPromise('react',function(name){
/** 守候上一步 实行终了以后 再实行 */
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('react',name);
resolve();
},1000);
});
});
}
start(){
/**
* promsie终究返回一个prosise 胜利resolve时
* .then即为终究回调
*/
this.hooks.promise('call end.').then(function(){
console.log('终究的回调');
});
}
}
let h = new Hook();
h.tap();
h.start();
/* 打印递次:
node call end.
react call end. -> 1s后打印
终究的回调 -> 1s后打印
*/
手动完成AsyncSeriesHook的Promise版本
class AsyncSeriesHook{
constructor(args){
this.tasks = [];
}
tapPromise(name,fn){
this.tasks.push(fn);
}
promise(...args){
/** 1 解构 拿到第一个first
* first是一个promise
*/
let [first, ...others] = this.tasks;
/** 4 应用reduce要领 累计实行
* 它终究返回的是一个Promsie
*/
return others.reduce((l,n)=>{
/** 1 下一步的实行依靠上一步的then */
return l.then(()=>{
/** 2 下一步实行依靠上一步效果 */
return n(...args);
});
},first(...args));
}
}
let h = new AsyncSeriesHook(['name']);
/** 定阅 */
h.tapPromise('react',(name)=>{
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('react',name);
resolve();
},1000);
});
});
h.tapPromise('node',(name)=>{
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('node',name);
resolve();
},1000);
});
});
/** 宣布 */
h.promise('end.').then(function(){
console.log('终究的回调函数');
});
/* 打印递次:
react end.
node end. -> 1s后打印
终究的回调函数 -> 1s后打印
*/
末了一个AsyncSeriesWaterfallHook:
AsyncSeriesWaterfallHook
AsyncSeriesWaterfallHook 异步的串行的瀑布钩子,起首 它是一个异步串行的钩子,同时 它的下一步依靠上一步的效果返回:
const { AsyncSeriesWaterfallHook } = require('tapable');
class Hook{
constructor(){
this.hooks = new AsyncSeriesWaterfallHook(['name']);
}
tap(){
this.hooks.tapAsync('node',function(name,cb){
setTimeout(()=>{
console.log('node',name);
/** 第一次参数是err, 第二个参数是通报给下一步的参数 */
cb(null,'第一步返回第二步的效果');
},1000);
});
this.hooks.tapAsync('react',function(data,cb){
/** 此回调要守候上一个回调实行终了后才最先实行
* 而且 data 是上一步return的效果.
*/
setTimeout(()=>{
console.log('react',data);
cb();
},1000);
});
}
start(){
this.hooks.callAsync('call end.',function(){
console.log('终究的回调');
});
}
}
let h = new Hook();
h.tap();
h.start();
/* 打印递次:
node call end.
react 第一步返回第二步的效果
终究的回调
*/
我们能够看到 第二步依靠了第一步返回的值, 而且它也是串行的钩子,完成它:
class AsyncParallelHook{
constructor(args){ /* args -> ['name']) */
this.tasks = [];
}
/** tap吸收两个参数 name和fn */
tap(name,fn){
/** 定阅:将fn放入到this.tasks中 */
this.tasks.push(fn);
}
start(...args){
let index = 0;
/** 1 拿到末了的终究的回调 */
let finalCallBack = args.pop();
let next = (err,data) => {
/** 拿到每一个task */
let task = this.tasks[index];
/** 2 假如没传task 或许悉数task都实行终了
* return 直接实行终究的回调finalCallBack()
*/
if(!task) return finalCallBack();
if(index === 0){
/** 3 实行第一个task
* 并通报参数为原始参数args
*/
task(...args, next);
}else{
/** 4 实行处第二个外的每一个task
* 并通报的参数 data
* data ->‘通报给下一步的效果’
*/
task(data, next);
}
index++;
}
/** 实行next() */
next();
}
}
let h = new AsyncParallelHook(['name']);
/** 定阅 */
h.tap('react',(name,cb)=>{
setTimeout(()=>{
console.log('react',name);
cb(null,'通报给下一步的效果');
},1000);
});
h.tap('node',(name,cb)=>{
setTimeout(()=>{
console.log('node',name);
cb();
},1000);
});
/** 宣布 */
h.start('end.',function(){
console.log('终究的回调函数');
});
/* 打印递次:
react end.
node 通报给下一步的效果
终究的回调函数
*/
AsyncSeriesWaterfallHook的Promise版本
const { AsyncSeriesWaterfallHook } = require('tapable');
class Hook{
constructor(){
this.hooks = new AsyncSeriesWaterfallHook(['name']);
}
tap(){
this.hooks.tapPromise('node',function(name){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('node',name);
/** 在resolve中把效果传给下一步 */
resolve('返回给下一步的效果');
},1000);
});
});
this.hooks.tapPromise('react',function(name){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('react',name);
resolve();
},1000);
});
});
}
start(){
this.hooks.promise('call end.').then(function(){
console.log('终究的回调');
});
}
}
let h = new Hook();
h.tap();
h.start();
/* 打印递次:
node call end.
react 返回给下一步的效果
终究的回调
*/
用Promsie完成很简单,手动完成它吧:
class AsyncSeriesHook{
constructor(args){
this.tasks = [];
}
tapPromise(name,fn){
this.tasks.push(fn);
}
promise(...args){
/** 1 解构 拿到第一个first
* first是一个promise
*/
let [first, ...others] = this.tasks;
/** 2 应用reduce要领 累计实行
* 它终究返回的是一个Promsie
*/
return others.reduce((l,n)=>{
return l.then((data)=>{
/** 3 将data传给下一个task 即可 */
return n(data);
});
},first(...args));
}
}
let h = new AsyncSeriesHook(['name']);
/** 定阅 */
h.tapPromise('react',(name)=>{
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('react',name);
resolve('promise-通报给下一步的效果');
},1000);
});
});
h.tapPromise('node',(name)=>{
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('node',name);
resolve();
},1000);
});
});
/** 宣布 */
h.promise('end.').then(function(){
console.log('终究的回调函数');
});
/* 打印递次:
react end.
node promise-通报给下一步的效果
终究的回调函数
*/
ok.至此,我们把tapable的钩子悉数剖析并手动完成终了。写文章不容易,喜好的话给个赞或许start~
代码在github上:mock-webpack-tapable