博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
webapck由浅入深——(Tapable)
阅读量:5876 次
发布时间:2019-06-19

本文共 13147 字,大约阅读时间需要 43 分钟。

webpack系列文章

Tapable和webpack

Tapable是基于发布订阅模式实现的一个类库,提供了许多Hook类,可创建许多钩子。在这些钩子里面调用内置或者用户在webpack.config.js中使用的插件,webpack在编译打包代码的各个环节会使用到。

Tapable中Hook分类

  • Taptable:
    • Sync*:
      • SyncHook
      • SyncBailHook
      • SyncWaterfallHook
      • SyncLoopHook
    • Async*:
      • AsyncParallelHook
      • AsyncParallelBailHook
      • AsyncSeriesHook
      • AsyncSeriesBailHook
      • AsyncSeriesWaterfallHook

Sync*型Hook

Sync*型的Hook里面的Hook都是同步执行的

SyncHook

串行同步执行,不关心返回值

class SyncHook {    constructor(){        this.tasks = [];    }    tap(name,task){        this.tasks.push(task);    }    call(){        this.tasks.forEach(task=>task(...arguments));    }}let queue = new SyncHook(['name']);queue.tap('1',function(name){  console.log(name,1);});queue.tap('2',function(name){  console.log(name,2);});queue.tap('3',function(name){  console.log(name,3);});queue.call('kbz');复制代码

SyncBailHook

串行同步执行,bail是保险丝的意思,有一个返回值不为null则跳过剩下的逻辑

class SyncBailHook {    constructor(){        this.tasks = [];    }    tap(name,task){        this.tasks.push(task);    }    call(){        let i=0,ret;        do {            ret=this.tasks[i++](...arguments);        } while (!ret);    }}let queue = new SyncBailHook(['name']);queue.tap('1',function(name){  console.log(name,1);  return 'Wrong';});queue.tap('2',function(name){  console.log(name,2);});queue.tap('3',function(name){  console.log(name,3);});queue.call('kbz');复制代码

SyncWaterfallHook

串行同步执行,Waterfall是瀑布的意思,前一个订阅者的返回值会传给后一个订阅者

class SyncWaterfallHook {    constructor(){        this.tasks = [];    }    tap(name,task){        this.tasks.push(task);    }    call(){        let [first,...tasks]=this.tasks;        tasks.reduce((ret,task)=>task(ret),first(...arguments));    }}let queue = new SyncWaterfallHook(['name']);queue.tap('1',function(name,age){  console.log(name,age,1);  return 1;});queue.tap('2',function(data){    console.log(data,2);    return 2;});queue.tap('3',function(data){  console.log(data,3);});queue.call('kbz',25);复制代码

SyncLoopHook

串行同步执行,Loop是循环往复的意思,订阅者返回true表示继续列表循环,返回undefine表示结束循环

class SyncLoopHook{    constructor() {        this.tasks=[];    }    tap(name,task) {        this.tasks.push(task);    }    call(...args) {            this.tasks.forEach(task => {            let ret=true;            do {                ret = task(...args);            }while(ret == true || !(ret === undefined))        });    }}let queue = new SyncLoopHook(['name']);let count = 0;queue.tap('1',function(name){    console.log(count++);    if(count==3){        return;    }else{        return true;    }});queue.call('kbz');复制代码

Async*型Hook

  • ASync*型的Hook里面的Hook分为异步串行和异步并行两种
  • ASync*型的Hook里面的Hook按照实现方式分为normal型、promise型
  • ASync*型的Hook支持tapAsync、tapPromise注册,通过调用callAsync、promise方式调用。

对于promise还不清楚的可以参考

AsyncParallelHook

并行异步执行,和同步执行的最大区别在于,订阅者中可以存在异步逻辑。

  • normal型
class AsyncParallelHook{    constructor() {        this.tasks=[];    }    tap(name,task) {        this.tasks.push(task);    }    call() {        let args=Array.from(arguments);        let callback=args.pop();    //将全部任务执行完毕后执行的回调        let i=0,size = this.tasks.length;        function done() {   //用来统计订阅者异步任务执行完成的个数            if (++i == size) {                callback(null);            }        }        this.tasks.forEach(task => {            task(...args,done);        });    }}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('kbz',err=>{    console.log(err);    console.timeEnd('cost');});复制代码
  • promise型
class AsyncParallelHook{    constructor() {        this.tasks=[];    }    tapPromise(name,task) {        this.tasks.push(task);    }    promise() {        let promises = this.tasks.map(task => task());        //Promise.all所有的Promsie执行完成会调用回调        return Promise.all(promises);       }}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('kbz').then(()=>{    console.timeEnd('cost');})复制代码

AsyncParallelBailHook

并行异步执行,bail是保险丝的意思,只要有一个异步逻辑返回不为null则会直接执行总的回调

  • normal型
class AsyncParallelBailHook{    constructor() {        this.tasks=[];    }    tapAsync(name,task) {        this.tasks.push(task);    }    callAsync() {        let args=Array.from(arguments);        let finalCallback=args.pop();        let count=0,total=this.tasks.length;        function done(err) {            if (err) {  //如果有返回值,则直接执行总的回调                return finalCallback(err);            } else {                if (++count == total) {                    return finalCallback();                }            }        }        for (let i=0;i
{ console.log(err); console.timeEnd('cost');});复制代码
  • promise型
class AsyncParallelBailHook{    constructor() {        this.tasks=[];    }    tapPromise(name,task) {        this.tasks.push(task);    }    promise() {        let args=Array.from(arguments);        let promises = this.tasks.map(task => task(...arguments));        return Promise.all(promises);    }}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();        },1000)    });});queue.tapPromise('2',function(name){    return new Promise(function(resolve,reject){        setTimeout(function(){            console.log(2);            //错误直接调用reject,那么会自动调用promise会捕捉到            reject();           },2000)    });});queue.tapPromise('3',function(name){    return new Promise(function(resolve,reject){        setTimeout(function(){            console.log(3);            resolve();        },3000)    });});queue.promise('kbz').then(()=>{    console.timeEnd('cost');},err => {    console.error(err);    console.timeEnd('cost');})复制代码

AsyncSeriesHook

串行异步执行,和并行异步执行的主要区别在于,会将下一个订阅的函数当成参数传给前一个订阅的函数,前一个订阅的函数控制运行。

  • normal型
class AsyncSeriesBailHook{    constructor() {        this.tasks=[];    }    tapAsync(name,task) {        this.tasks.push(task);    }    callAsync() {        let args=Array.from(arguments);        let callback=args.pop();        let i=0,size = this.tasks.length;        let next=(err) => {            let task=this.tasks[i++];            //将下一个订阅者传递给前一个订阅者调用            task?task(...args,next):callback();         }        next();    }}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('kbz',err=>{    console.log(err);    console.timeEnd('cost');});复制代码
  • promise型
class AsyncSeriesHook{    constructor() {        this.tasks=[];    }    tapPromise(name,task) {        this.tasks.push(task);    }    promise() {        let promises=this.tasks.map(item => item());        //将后一个promise放到前一个promise的then中执行,前一个执行完会自动执行then里面的异步逻辑        return promises.reduce((a,b) => a.then(()=>b));    }}let queue=new AsyncSeriesHook(['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){        setTimeout(function(){            console.log(2);            resolve();        },2000)    });});queue.tapPromise('3',function(name,callback){    return new Promise(function(resolve){        setTimeout(function(){            console.log(3);            resolve();        },3000)    });});queue.promise('kbz').then(data=>{    console.log(data);    console.timeEnd('cost');});复制代码

AsyncSeriesBailHook

串行异步执行,bail是保险丝的意思,只要有一个异步逻辑返回不为null则会跳出来直接执行最后的回调

class AsyncSeriesBailHook{    constructor() {        this.tasks=[];    }    tapAsync(name,task) {        this.tasks.push(task);    }    callAsync() {        let args=Array.from(arguments);        let callback=args.pop();        let i=0,size = this.tasks.length;        let next=(err) => {            //如果返回的不是null则跳出后面逻辑,执行最后的回调            if (err) return  callback(err);             let task=this.tasks[i++];            task?task(...args,next):callback();        }        next();    }}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('kbz',err=>{    console.log(err);    console.timeEnd('cost');});复制代码
  • promise型
class AsyncSeriesHook{    constructor() {        this.tasks=[];    }    tapPromise(name,task) {        this.tasks.push(task);    }    promise() {        let promises=this.tasks.map(item => item());        //将后一个promise放到前一个promise的then中执行,前一个执行完会自动执行then里面的异步逻辑        return promises.reduce((a,b) => a.then(()=>b));    }}let queue=new AsyncSeriesHook(['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){        setTimeout(function(){            console.log(2);            reject();   //使用reject那么就会直接跳出后面的逻辑        },2000)    });});queue.tapPromise('3',function(name,callback){    return new Promise(function(resolve){        setTimeout(function(){            console.log(3);            resolve();        },3000)    });});queue.promise('kbz').then(data=>{    console.log(data);    console.timeEnd('cost');});复制代码

AsyncSeriesWaterfallHook

串行异步执行,Waterfall是瀑布的意思,前一个订阅者的返回值会传给后一个订阅者

  • normal型
class AsyncSeriesWaterfallHook{    constructor() {        this.tasks=[];    }    tapAsync(name,task) {        this.tasks.push(task);    }    callAsync() {        let args=Array.from(arguments);        let callback=args.pop();        let i=0,size = this.tasks.length;        let next=(err,data) => {            if (err) return  callback(err);            let task=this.tasks[i++];            if (task) {                //除了第一个需要传arguments,后面的接受前一个的返回值                if (i==0) {                     task(...args,next);                } else {                    task(data,next);                }            } else {                callback(err,data);            }        }        next();    }}let queue = new AsyncSeriesWaterfallHook(['name']);console.time('cost');queue.tapAsync('1',function(name,callback){   setTimeout(function(){       console.log(1);       callback(null,1);   },1000)});queue.tapAsync('2',function(data,callback){    setTimeout(function(){        console.log(2);        callback(null,2);    },2000)});queue.tapAsync('3',function(data,callback){    setTimeout(function(){        console.log(3);        callback(null,3);    },3000)});queue.callAsync('kbz',(err,data)=>{    console.log(err,data);    console.timeEnd('cost');});复制代码
  • promise型
class AsyncSeriesHook{    constructor() {        this.tasks=[];    }    tapPromise(name,task) {        this.tasks.push(task);    }    promise() {        let promises=this.tasks.map(item => item());        //将data传给下一个订阅者即可        return promises.reduce((a,b) => a.then((data)=>b));    }}let queue=new AsyncSeriesHook(['name']);console.time('cost');queue.tapPromise('1',function(name){   return new Promise(function(resolve){       setTimeout(function(){           console.log(1);           resolve(1);       },1000)   });});queue.tapPromise('2',function(name,callback){    return new Promise(function(resolve){        setTimeout(function(){            console.log(2);            resoleve(2);          },2000)    });});queue.tapPromise('3',function(name,callback){    return new Promise(function(resolve){        setTimeout(function(){            console.log(3);            resolve(3);        },3000)    });});queue.promise('kbz').then(data=>{    console.log(data);    console.timeEnd('cost');});复制代码

结语:

tapable就是基于发布订阅机制实现的,这样能够用队列存储一系列的回调,在webapck的生命周期的各个阶段调用。

转载地址:http://pckix.baihongyu.com/

你可能感兴趣的文章
java String/StringBuilder 方法
查看>>
QTP学习笔记1
查看>>
【Linux网络编程】广播地址介绍
查看>>
iOS8新特性扩展(Extension)应用之二——分享插件
查看>>
数据迁移工具sqoop入门
查看>>
JDBC编程 之 增删改查
查看>>
《高效程序员的修炼》 读书笔记
查看>>
Android Animation动画详解(二): 组合动画特效
查看>>
《Netty权威指南》目录
查看>>
iGraph 2015双促复盘总结
查看>>
Android 开发第一弹:倒计时
查看>>
Linux Mac之间文件传输
查看>>
(六)unsigned的用法
查看>>
iOS开发- 以图搜图功能实现 (源码+解析)
查看>>
二维码篇【一】【JS】使用jquery.qrcode生成二维码
查看>>
LevelDB:Bloom源码精读——数据结构
查看>>
一个设置访问权限的实例
查看>>
【Android】 banner+tab吸顶+viewpager切换+刷新加载之实现
查看>>
找零问题与动态规划
查看>>
Leetcode279完全平方数
查看>>