深切明白Webpack中心模块Tapable钩子[异步版]

接上一篇文章 深切明白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

    原文作者:Funky_Tiger
    原文地址: https://segmentfault.com/a/1190000018312930
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞