腦袋疼的Webpack-tapable

tapable據說了好久,終於下定決心繫統學習一下javascript

Q1:tapable解決的問題?

  1. tapable是個獨立的庫
  2. webpack中大量使用了這個庫
  3. tapable主要是用來處理事件,解決的問題有點相似EventEmitter,不過功能更增強大

Q2:tapable方法有哪些?

const {
    SyncHook,
    SyncBailHook,
    SyncWaterfallHook,
    SyncLoopHook,
    AsyncParallelHook,
    AsyncParallelBailHook,
    AsyncSeriesHook,
    AsyncSeriesBailHook,
    AsyncSeriesWaterfallHook 
 } = require("tapable");
複製代碼

好的,方法一共是上述這麼多,第一眼看過去,懵逼樹下你和我,因此咱們仍是一點點來,一個個的分析、學習和了解前端

Q3:啥是SyncHook?

先來個使用的例子,例如前端開發者須要掌握哪些技能?java

step1:首先咱們要明確羣體是前端開發

const {SyncHook}= require('tapable');
const FrontEnd = new SyncHook();
複製代碼

ok,就是上面這兩句,咱們建立了個FrontEnd前端開發node

step2:前端開發須要掌握哪些技能,例如webpack、react對吧

FrontEnd.tap('webpack',()=>{
  console.log("get webpack")
});
FrontEnd.tap('react',()=>{
  console.log("get react")
});
複製代碼

ok,上面的tap就是用來綁定事件的,爲前端開發添加了兩個技能react

step3:技能須要學習才能掌握,因此咱們要有學習的動做

FrontEnd.learn=()=>{
  FrontEnd.call()
};
FrontEnd.learn();
複製代碼

step4:查看執行結果

get webpack
get react
複製代碼

能夠看到,經過上面的調用,咱們的前端開發已經學會了react、webpackjquery

step5:傳參

前面知道FrontEnd這個羣體,須要學react、webpack,但落到我的角度,究竟哪個開發者掌握這些技能了呢?webpack

const {SyncHook}= require('tapable');
const FrontEnd = new SyncHook();
FrontEnd.tap('webpack',(name)=>{
  console.log(name+" get webpack")
});
FrontEnd.tap('react',(name)=>{
  console.log(name+" get react")
});
FrontEnd.start=(name)=>{
  FrontEnd.call(name)
};
FrontEnd.start('xiaoming');
複製代碼

修改前面的代碼,添加參數,預期是輸出xxx get reactweb

step6: 查看輸出結果

undefined get webpack
undefined get react
複製代碼

最終結果是undefined,也就是參數沒傳進去redux

step7:爲SyncHook添加約定參數

這是由於const FrontEnd = new SyncHook();建立SyncHook的時候沒有約定參數,只要爲其添加參數便可,以下:api

const {SyncHook}= require('tapable');
const FrontEnd = new SyncHook(['name']);// 添加參數約定
FrontEnd.tap('webpack',(name)=>{
  console.log(name+" get webpack")
});
FrontEnd.tap('react',(name)=>{
  console.log(name+" get react")
});
FrontEnd.start=(name)=>{
  FrontEnd.call(name)
};
FrontEnd.start('xiaoming');
複製代碼

最終輸出:

xiaoming get webpack
xiaoming get react
複製代碼

SyncHook總結

  1. SyncHook目前來看比較像訂閱發佈
  2. 就像jquery中的add、fire方法,只不過這裏是tap、call

Q4:SyncHook如何實現?

SyncHook實現比較簡單,就是最簡單的訂閱發佈

class SyncHook {
  constructor(limit = []){
    this.limit= limit;
    this.tasks = [];
  }
  tap(name,task){
    this.tasks.push(task);
  }
  call(...args){
    const param =  args.slice(0,this.limit.length);
    this.tasks.forEach(item=>item(...param));
  }
}
複製代碼
  1. limit是用來作參數校驗的
  2. tasks用來收集訂閱
  3. tap方法用來想tasks中添加方法
  4. call方法,先檢驗參數,而後再執行全部的已訂閱方法

總結:原理比較簡單,沒有太多技術含量,主要就是一個同步的鉤子函數

Q5:啥是SyncBailHook?

熔斷機制,若是前一個事件return true,則再也不執行下一個,仍是前面的例子:

const {SyncBailHook} =require('tapable');
const FrontEnd = new SyncBailHook(['name']);
FrontEnd.tap('webpack',(name)=>{
  console.log(name+" get webpack ")
});
FrontEnd.tap('react',(name)=>{
  console.log(name+" get react")
});
FrontEnd.start=(...args)=>{
  FrontEnd.call(...args)
};
FrontEnd.start('xiaoming');
複製代碼

此時,把函數從SyncHook換成SyncBailHook,執行的結果沒有任何區別

but,思考一下,學習很容易會學不下去,因此修改一下咱們的例子:

const {SyncBailHook} =require('tapable');
const FrontEnd = new SyncBailHook(['name']);
FrontEnd.tap('webpack',(name)=>{
  console.log(name+" get webpack ")
  return '學不動了啊!';
});
FrontEnd.tap('react',(name)=>{
  console.log(name+" get react")
});
FrontEnd.start=(...args)=>{
  FrontEnd.call(...args)
};
FrontEnd.start('xiaoming');
複製代碼

此時僅輸出:

xiaoming get webpack 
複製代碼

後面的react沒有執行

總結:

  1. SyncBailHook主要解決的問題是條件阻塞
  2. 當訂閱事件符合某一判斷時,再也不執行下面的流程
  3. 應用場景,場景不斷深刻的場景,a、a+b、a+b+c、a+b+c+d這種場景

Q6:SyncBailHook如何實現?

SyncBailHook也十分簡單,仍是以前那個例子:

class SyncBailHook {
  constructor(limit = []){
    this.limit= limit;
    this.tasks = [];
  }
  tap(name,task){
    this.tasks.push(task);
  }
  call(...args){
    const param =  args.slice(0,this.limit.length);
    this.tasks.some(item=>item(...param));// 只改了一行
  }
}
複製代碼

能夠看到,和上面SyncHook十分類似,無非就是把執行函數forEach,換成some,由於some是阻塞式執行,當返回true,則不會執行後面的內容

Q7:啥是SyncWaterfullHook?

仍是先來個使用的例子,例如前端,技能都是一個個學的,要學完webpack再學react,例如:

const {SyncWaterfallHook} = require('tapable');
const FrontEnd = new SyncWaterfallHook(['name']);
FrontEnd.tap('webpack',(name)=>{
  console.log(name+" get webpack ")
  return '學完webpack了,該學react了';
});
FrontEnd.tap('react',(name)=>{
  console.log(name+" get react")
});
FrontEnd.start=(...args)=>{
  FrontEnd.call(...args)
};
FrontEnd.start('xiaoming');
複製代碼

此時輸出:

xiaoming get webpack 
學完webpack了,該學react了 get react
複製代碼
  1. SyncWaterfallHook會將前一個任務的執行結果,傳遞給後一個
  2. 主要使用場景是處理邏輯之間相互依賴
  3. 實際效果和redux中的compose方法一毛同樣

Q8:SyncWaterfullHook如何實現?

class SyncWaterfallHook {
  constructor(limit = []){
    this.limit= limit;
    this.tasks = [];
  }
  tap(name,task){
    this.tasks.push(task);
  }
  call(...args){
    const param =  args.slice(0,this.limit.length);
    const [first,...others] = this.tasks;
    const ret = first(...param);
    others.reduce((pre,next)=>{
      return next(pre);
    },ret)
  }
}
複製代碼

SyncWaterfallHook實現也比較簡單

  1. 徹底按照redux的compose來實現就行
  2. 第一步,取出第一個執行,並拿到結果ret
  3. 第二步,將結果ret,看成reduce的參數傳遞進去
  4. 第三步,遍歷,不斷把參數傳給下一個函數

總結:SyncWaterfallHook主要仍是用於函數之間對結果存在依賴的場景

Q9:啥是SyncLoopHook?

仍是前面的例子,若是一次學不懂一門技術,那就要多學幾遍,例如:

const FrontEnd = new SyncLoopHook(['name']);
let num = 0;
FrontEnd.tap('webpack',(name)=>{
  console.log(name+" get webpack ")
  return ++num === 3?undefined:'再學一次';
});
FrontEnd.tap('react',(name)=>{
  console.log(name+" get react")
});
FrontEnd.start=(...args)=>{
  FrontEnd.call(...args)
};
FrontEnd.start('xiaoming');
複製代碼

上面執行的結果是:

xiaoming get webpack 
xiaoming get webpack 
xiaoming get webpack 
xiaoming get react
複製代碼
  1. SyncLoopHook任務可以執行屢次
  2. 返回undefined則中止執行,返回非undefined則繼續執行當前任務

總結:主要場景是同一任務,須要執行屢次

Q10:SyncLoopHook如何實現?

class SyncLoopHook {
  constructor(limit = []){
    this.limit= limit;
    this.tasks = [];
  }
  tap(name,task){
    this.tasks.push(task);
  }
  call(...args){
    const param =  args.slice(0,this.limit.length);
    let index = 0;
    while(index<this.tasks.length){
      const result = this.tasks[index](...param);
      if(result === undefined){
        index++;
      }
    }
  }
}
複製代碼
  1. 上面的實現是經過計數
  2. 若是結果不爲undefined則下標index不移動
  3. 若是結果爲undefined則下標index增長

也能夠換doWhile來實現

class SyncLoopHook {
  constructor(limit = []){
    this.limit= limit;
    this.tasks = [];
  }
  tap(name,task){
    this.tasks.push(task);
  }
  call(...args){
    const param =  args.slice(0,this.limit.length);
   this.tasks.forEach(task=>{
     let ret;
     do{
      ret = task(...param);
     }while(ret!=undefined)
   })
  }
}
複製代碼
  1. 這種實現沒有下標概念了
  2. 直接遍歷tasks任務組,若是任務組中某一個任務執行的結果不是undefined則再次執行

總結:SyncLoopHook這個使用場景相對較少,不過了解一下也好

Q11:啥是AsyncParralleHook?

前面瞭解的都是同步hook,更關鍵的是異步hook

舉個例子,同窗小王說去學前端了,但你也不知道他何時學完,只有他學完告訴你,你才知道他學完了,例:

const {AsyncParallelHook} = require('tapable');
const FrontEnd = new AsyncParallelHook(['name']);
FrontEnd.tapAsync('webpack',(name,cb)=>{
  setTimeout(() => {
    console.log(name+" get webpack ")
    cb();
  }, 1000);
 
});
FrontEnd.tapAsync('react',(name,cb)=>{
  setTimeout(() => {
    console.log(name+" get react")
    cb();
  }, 1000);
});
FrontEnd.start=(...args)=>{
  FrontEnd.callAsync(...args,()=>{
    console.log("end");
  })
};
FrontEnd.start('小王');
複製代碼

最終輸出:

小王 get webpack 
小王 get react
end
複製代碼
  1. AsyncParralleHook是異步並行鉤子
  2. 使用場景,例如同時發起對兩個接口的請求
  3. 注意:此次註冊事件,再也不是tap了,而是tapAsync
  4. 注意:此次的事件執行,再也不是call了,而是callAsync
  5. 能夠看出tapable中區分了同步、異步的訂閱和發佈
  6. 注意:想要讓全部異步執行完成後,接收到通知,須要執行cb()

Q12:AsyncParralleHook如何實現?

class AsyncParallelHook {
  constructor(limit = []){
    this.limit= limit;
    this.tasks = [];
  }
  tapAsync(name,task){
    this.tasks.push(task);
  }
  callAsync(...args){
    const finalCallBack = args.pop();
    const param =  args.slice(0,this.limit.length);
    let index = 0;
    const done=()=>{
      index++;
      if(index === this.tasks.length){
        finalCallBack();
      }
    }
    this.tasks.forEach(item=>item(...param,done))
  }
}
複製代碼
  1. AsyncParallelHook最簡單就是經過計數
  2. 在實例上添加一個計數器
  3. 而後遍歷tasks,當任務成功個數與任務總數相同時,執行finalCallBack

總結:AsyncParallelHook解決的問題和promise.all相似,都是用於解決異步並行的問題

Q13:AsyncParralleHook(2)如何使用promise?

前面雖然用:AsyncParralleHook可以解決異步,但並無使用primise,也沒有類promise的概念

const {AsyncParallelHook} = require('tapable');
const FrontEnd = new AsyncParallelHook(['name']);
FrontEnd.tapPromise('webpack',(name)=>{
  return new Promise((resolve)=>{
    setTimeout(() => {
      console.log(name+" get webpack ")
      resolve();
    }, 1000);
  })
});
FrontEnd.tapPromise('react',(name,cb)=>{
  return new Promise((resolve)=>{
    setTimeout(() => {
      console.log(name+" get react ")
      resolve();
    }, 1000);
  })
});
FrontEnd.start=(...args)=>{
  FrontEnd.promise(...args).then(()=>{
    console.log("end");
  })
};
FrontEnd.start('小王');
複製代碼

調用上面的api後,輸出:

小王 get webpack 
小王 get react 
end
複製代碼
  1. 注意:此時綁定事件的方法叫作tapPromise
  2. 注意:此時執行事件的方法叫作promise

總結:

  1. tapable共有三種事件綁定方法:tap、tapAsync、tapPromise
  2. tapable共有三種事件執行方法:call、callAsync、promise

Q14:AsyncParralleHook(2)promise版如何實現?

class AsyncParallelHook {
  constructor(limit = []){
    this.limit= limit;
    this.tasks = [];
  }
  tapPromise(name,task){
    this.tasks.push(task);
  }
  promise(...args){
    const param =  args.slice(0,this.limit.length);
    const tasks = this.tasks.map(task=>task(...param));
    return Promise.all(tasks)
  }
}
複製代碼
  1. 核心就是實現兩個方法,tapPromise和promise
  2. tapPromise其實和以前的tap沒有明顯區別(簡單實現的問題)
  3. promise的話,其實就是返回一個Promise.all

Q15:啥是AsyncParallelBailHook?

AsyncParallelBailHook這個鉤子和前面的鉤子不太同樣 按前面的例子來說:

  1. 同窗小王說去學前端了,但你也不知道他何時學完,只有他學完告訴你,你才知道他學完了
  2. 小王學了webpack,學崩了,告訴了你
  3. 你據說小王學崩了,你就覺得他學不下去了,你就對你們夥說,小王學崩了
  4. 可是小王同時也學了react卻咬牙學完了
  5. 雖然學完了,但你已經對外宣佈小王崩了,很打臉,因此就當不知道了

這就是AsyncParallelBailHook處理的事情

const {AsyncParallelBailHook} = require('tapable');
const FrontEnd = new AsyncParallelBailHook(['name']);
FrontEnd.tapPromise('webpack',(name)=>{
  return new Promise((resolve,reject)=>{
    setTimeout(() => {
      console.log(name+" get webpack ")
      reject('小王學崩了!');
    }, 1000);
  })
});
FrontEnd.tapPromise('react',(name,cb)=>{
  return new Promise((resolve)=>{
    setTimeout(() => {
      console.log(name+" get react ")
      resolve();
    }, 2000);
  })
});
FrontEnd.start=(...args)=>{
  FrontEnd.promise(...args).then(()=>{
    console.log("end");
  },(err)=>{
    console.log("據說:",err)
  })
};
FrontEnd.start('小王');
複製代碼

上面代碼執行結果是:

小王 get webpack 
據說: 小王學崩了!
小王 get react 
複製代碼
  1. 上面例子,第一個並行任務返回了reject
  2. reject只要不是undefined,就會直接進入promise.all的catch
  3. 異步任務,react仍是會執行,但成功後沒有處理了

再看一個例子:

const {AsyncParallelBailHook} = require('tapable');
const FrontEnd = new AsyncParallelBailHook(['name']);
FrontEnd.tapPromise('webpack',(name)=>{
  return new Promise((resolve,reject)=>{
    setTimeout(() => {
      console.log(name+" get webpack ")
      reject();
    }, 1000);
  })
});
FrontEnd.tapPromise('react',(name,cb)=>{
  return new Promise((resolve)=>{
    setTimeout(() => {
      console.log(name+" get react ")
      resolve();
    }, 2000);
  })
});
FrontEnd.start=(...args)=>{
  FrontEnd.promise(...args).then(()=>{
    console.log("end");
  },(err)=>{
    console.log("據說:",err)
  })
};
FrontEnd.start('小王');
複製代碼

和上面就改了1行,就是reject內容爲空,此時輸出:

小王 get webpack 
小王 get react 
end
複製代碼
  1. 此時即使調用了reject也不會進入到catch
  2. reject返回空,後面的任務也會照常執行

總結:

  1. AsyncParallelBailHook,若是返回真值,則直接會走進catch
  2. 不管返回結果是什麼,全部任務都會執行
  3. 主要場景是,並行請求3個接口,隨便哪個返回結果都行,只要返回了,就對返回進行處理(走catch)
  4. 若是用來處理同步,則和SyncBailHook效果同樣
  5. 若是處理tapSync,則遇到return true最終的callback不會執行
  6. 若是處理promise,則遇到rejcet(true),則直接進入catch

Q16:AsyncParallelBailHook如何實現?

這個AsyncParallelBailHook真真燒腦了好一會

class AsyncParallelBailHook {
  constructor(limit = []){
    this.limit= limit;
    this.tasks = [];
  }
  tapPromise(name,task){
    this.tasks.push(task);
  }
  promise(...args){
    const param =  args.slice(0,this.limit.length);
    const tasks = this.tasks.map(task=>{
      return new Promise((resolve,reject)=>{
        task(...param).then((data)=>{
          resolve(data);
        },(err)=>{
          err? reject(err):resolve();
        });
      })
    });
    return Promise.all(tasks)
  }
}
複製代碼
  1. 正常狀況下,promise.all中任意一個任務reject,就會進入統一的catch
  2. 但咱們須要的是根據reject的值來判斷是否走如catch
  3. 因此咱們在原有task外,再包一層promise
  4. 若是reject值爲真,則執行reject
  5. 若是reject值爲假,則執行resolve,就當什麼也沒發生

Q17:啥是AsyncSeriesHook?

前面講的是異步並行,如今該說異步串行了,例如小王,學完webpack纔去學的react,你也不知道他何時學完,但他學完一個就會告訴你一下,例:

const {AsyncSeriesHook} = require('tapable');
const FrontEnd = new AsyncSeriesHook(['name']);
console.time('webpack');
console.time('react');
FrontEnd.tapPromise('webpack',(name,cb)=>{
  return new Promise((resolve,reject)=>{
    setTimeout(() => {
      console.log(name+" get webpack ")
      console.timeEnd('webpack');
      resolve();
    }, 1000);
  })
});
FrontEnd.tapPromise('react',(name,cb)=>{
  return new Promise((resolve)=>{
    setTimeout(() => {
      console.log(name+" get react ")
      console.timeEnd('react');
      resolve();
    }, 1000);
  })
});
FrontEnd.start=(...args)=>{
  FrontEnd.promise(...args).then(()=>{
    console.log("end");
  })
};
FrontEnd.start('小王');
複製代碼

上面代碼執行結果:

小王 get webpack 
webpack: 1010.781ms
小王 get react 
react: 2016.598ms
end
複製代碼
  1. 兩個異步任務,變成了串行
  2. 從時間可以得出,兩個1s的異步的任務,串行後總時間變成了2s

總結:AsyncSeriesHook解決的問題是異步串行,例如node的os.cpus()有限,能夠把任務分批次執行,這樣對性能有保障

Q18:AsyncSeriesHook如何實現?

class AsyncSeriesHook {
  constructor(limit = []){
    this.limit= limit;
    this.tasks = [];
  }
  tapPromise(name,task){
    this.tasks.push(task);
  }
  promise(...args){
    const param =  args.slice(0,this.limit.length);
    const [first,...others] = this.tasks;
    return others.reduce((pre,next)=>{
      return pre.then(()=>next(...param))
    },first(...param))
  }
}
複製代碼
  1. 實現核心就是promise串行
  2. 取出第一個任務,執行拿到promise實例,而後經過reduce遍歷

Q19:啥是AsyncSeriesBailHook?

仍是前面的例子,若是小王學前端,學了webapck就完全放棄了,那後面的react也就不用學了

const {AsyncSeriesBailHook} = require('tapable');
const FrontEnd = new AsyncSeriesBailHook(['name']);
console.time('webpack');
console.time('react');
FrontEnd.tapPromise('webpack',(name,cb)=>{
  return new Promise((resolve,reject)=>{
    setTimeout(() => {
      console.log(name+" get webpack ")
      console.timeEnd('webpack');
      reject('小王完全放棄了');
    }, 1000);
  })
});
FrontEnd.tapPromise('react',(name,cb)=>{
  return new Promise((resolve)=>{
    setTimeout(() => {
      console.log(name+" get react ")
      console.timeEnd('react');
      resolve();
    }, 1000);
  })
});
FrontEnd.start=(...args)=>{
  FrontEnd.promise(...args).then(()=>{
    console.log("end");
  }).catch((err)=>{
    console.log("err",err)
  })
};
FrontEnd.start('小王');
複製代碼

上面代碼輸出:

小王 get webpack 
webpack: 1010.518ms
err 小王完全放棄了
複製代碼
  1. 上面的代碼只執行到webpack
  2. AsyncSeriesBailHook,任務若是return,或者reject,則阻塞了

場景:主要是異步串行,若是某一個任務執行的結果reject或者return,那麼後面的都將再也不執行

Q20:AsyncSeriesBailHook如何實現?

class AsyncSeriesBailHook {
  constructor(limit = []){
    this.limit= limit;
    this.tasks = [];
  }
  tapPromise(name,task){
    this.tasks.push(task);
  }
  promise(...args){
    const param =  args.slice(0,this.limit.length);
    const [first,...others] = this.tasks;
    return new Promise((resolve,reject)=>{
      others.reduce((pre,next,index,arr)=>{
        return pre
          .then(()=>next(...param))
          .catch((err=>{
            arr.splice(index,arr.length-index);
            reject(err);
          })).then(()=>{
            (index+1 === arr.length) && resolve();
          })
      },first(...param))
    })
  }
}
複製代碼

AsyncSeriesBailHook實現難度要高不少

  1. 首先在reduce外再包一層promise
  2. 當遇到任何一個子任務進入catch的時候,則將reduce的第四個參數arr切割,使其沒法再向下進行,也就是中止reduce的繼續
  3. 同時全部promise後面再添加一個後置then,用來檢測是否所有執行完成
  4. 爲何使用index+1,是由於後置then確定是最後一個任務,但遍歷index還處於上一個下標,因此只要加1就好

Q21:啥是AsyncSeriesWaterfallHook?

SyncWaterFallHook前面已經瞭解過了,就是前一個執行完的結果會傳遞給下一個執行函數,和AsyncSeriesWaterfallHook的區別就是,一個是同步一個是異步

具體來講,例如只有一本教材,小王學完,小張才能學

const FrontEnd = new AsyncSeriesWaterfallHook(['name']);
FrontEnd.tapAsync('webpack',(name,cb)=>{
    setTimeout(() => {
      console.log(name+" get webpack ")
      cb(null,'小李');
    }, 1000);
});
FrontEnd.tapAsync('webpack',(name,cb)=>{
  setTimeout(() => {
    console.log(name+" get webpack ")
    cb(null,'小張');
  }, 1000);
});
FrontEnd.tapAsync('webpack',(name,cb)=>{
  setTimeout(() => {
    console.log(name+" get webpack ")
    cb(null,'小紅');
  }, 1000);
});
FrontEnd.start=(...args)=>{
  FrontEnd.callAsync(...args,(data)=>{
    console.log("全學完了",)
  })
};
FrontEnd.start('小王');
複製代碼

上面代碼,最終輸出:

小王 get webpack 
小李 get webpack 
小張 get webpack 
全學完了
複製代碼

總結:這個的用法和SyncWaterFallHook的用法一致

Q22:AsyncSeriesWaterfallHook如何實現?

class AsyncSeriesWaterfallHook {
  constructor(limit = []){
    this.limit= limit;
    this.tasks = [];
  }
  tapAsync(name,task){
    this.tasks.push(task);
  }
  callAsync(...args){
    const param =  args.slice(0,this.limit.length);
    const finalCallBack = args.pop();
    let index = 0;
    const next = (err,data)=>{
      const task = this.tasks[index];
      if(!task)return finalCallBack();
      if(index === 0){
        task(...param,next)
      }else{
        task(data,next)
      }
      index++;
    }
    next();
  }
}
複製代碼
  1. 主要是經過封裝一個回調函數next
  2. 而後不斷調用任務隊列中的任務,調用的時候,再傳遞相同的回調函數進去

prmise版本的實現以下:

class AsyncSeriesWaterfallHook {
  constructor(limit = []){
    this.limit= limit;
    this.tasks = [];
  }
  tapPromise(name,task){
    this.tasks.push(task);
  }
  promise(...args){
    const param =  args.slice(0,this.limit.length);
    const [first,...others] = this.tasks;
    return others.reduce((pre,next)=>{
      return pre.then((data)=>{
        return data?next(data):next(...param);
      })
    },first(...param))
  }
}
複製代碼
  1. promise的實現要相對簡單一些
  2. 主要去看then方法中是否有內容,若是有的話,則傳遞個下一個函數,若是沒有,則用初始參數

總結

  1. tapable的各AsyncHook都同時支持tap、tapAsync、tapPromise
  2. tapable主要解決的是事件流轉的問題,各個Hook使用的場景各有不一樣
  3. tapable主要應用在webpack的各個生命週期中,具體的實踐還須要結合webpack原理去看

引用

tapable使用指南

相關文章
相關標籤/搜索