webpack源碼分析——tapable

Webpack的整個流程是經過tapable的事件流機制串聯起來。理解tapable對於閱讀源代碼的做用極大。本文分析的Tapable源碼的版本是0.2.7。webpack

1、tapable用途

tapable中大量的API主要是爲了實現兩個功能,一個做用是經過apply方法在complier中註冊插件;另外一個做用就是實現事件機制。web

2、tapable中的apply方法

apply方法的源碼:app

源碼意思很明顯,就是調用傳入對象的apply方法。在webpack中,這個傳入的對象就是插件的實例對象。異步

一個插件的簡單實現大體以下所示:函數

實際的例子以下:spa

var compiler = new Complier();插件

compiler.apply(new SimplePlugin());3d

3、實現事件機制的其餘API

 tapable中其餘的API都是爲實現事件機制準備。webpack中的事件機制正是經過tapable實現的。須要進行事件處理的類經過繼承tapable類擁有事件處理的能力。下面咱們先看看tapable中是如何實現事件機制的。對象

所謂的事件處理,就是觸發事件和監聽事件blog

觸發事件的方法:applyPlugins、applyPlugins0、applyPlugins一、applyPlugins2;applyPluginsWaterfall、applyPluginsWaterfall0、applyPluginsWaterfall一、applyPluginsWaterfall2;applyPluginsBailResult、applyPluginsBailResult一、applyPluginsBailResult二、applyPluginsBailResult三、applyPluginsBailResult四、applyPluginsBailResult5;applyPluginsAsyncSeries、applyPluginsAsync、applyPluginsAsyncSeries1;applyPluginsAsyncSeriesBailResult、applyPluginsAsyncSeriesBailResult1;applyPluginsAsyncWaterfall;applyPluginsParallel;applyPluginsParallelBailResult、applyPluginsParallelBailResult1。

監聽事件的方法:plugin

webpack中實現事件機制大概分爲三步:

第一步、須要實例化Tapable類或者實例化繼承自tapable的類

var tapable = new Tapable();

第二步、監聽特定的事件(至關於JS中的addEventListerner)

tapable.plugin("test", function(a,b,callback){
    console.log('函數1:'+a+b);
    callback();
});

第三步、觸發特定的事件(至關於trigger方法)

tapable.applyPluginsAsync("test", '123','qeeqeq', function(){

    console.log('cb4');
});

tapable中監聽事件的方法就只有一個plugin方法,觸發事件的方法有applyPlugins、applyPluginsWaterfall等等,下面詳細介紹一下這些觸發事件的方法。

3.1 觸發事件的分類及詳細說明

3.1.1 applyPlugins、applyPlugins0、applyPlugins一、applyPlugins2方法

 applyPlugins方法使用說明:

用法:

var tapable = new Tapable();

tapable.applyPlugins('eventname', param1, param2, ...... paramn),

tapable.plugin('eventname', function(param1, param2,...... paramn){})

applyPlugins0使用說明:

源碼:

用法:

var tapable = new Tapable();

tapable.applyPlugins0('eventname');

tapable.plugin('eventname', funtion(){});

applyPlugins1的使用說明:

源碼:

用法:

var tapable = new Tapable();

tapable.applyPlugins0('eventname', param1);

tapable.plugin('eventname', funtion(param1){});

applyPlugins2的使用說明:

源碼:

用法:

var tapable = new Tapable();

tapable.applyPlugins0('eventname', param1, param2);

tapable.plugin('eventname', funtion(param1, param2){});

小結:applyPlugins0、applyPlugins一、applyPlugins2用法與applyPlugins相似,只是監聽函數對應的參數不一樣而已。applyPlugins0對應的監聽函數沒有參數;applyPlugins1對應的監聽函數有一個參數;applyPlugins2對應的監聽函數有兩個參數。

3.1.2 applyPluginsWaterfall、applyPluginsWaterfall0、applyPluginsWaterfall一、applyPluginsWaterfall2

這組方法的意思是觸發某個特定的事件,這個特定的事件會被一系列的流程監聽。每一個流程處理完後,將結果做爲參數傳遞給下一個監聽函數繼續處理,直至全部的監聽函數執行完畢。最終觸發事件的函數獲取全部監聽函數處理的結果。

 applyPluginsWaterfall使用說明:

源碼:

用法:

 var tapable = new Tapable();

 tapable.plugin('eventname', function(processValue, param1, param2,......, paramn){});

 tapable.plugin('eventname', function(processValue, param1, param2,......, paramn){});

 var result = tapable.applyPluginsWaterfall('eventname', defaultValue, param1, param2,......paramn);

applyPluginsWaterfall0使用說明:

源碼:

 

用法:

var tapable = new Tapable();

 tapable.plugin('eventname', function(processValue){});

 tapable.plugin('eventname', function(processValue){});

 var result = tapable.applyPluginsWaterfall('eventname', defaultValue);

applyPluginsWaterfall1使用說明:

源碼:

 

用法:

 var tapable = new Tapable();

 tapable.plugin('eventname', function(processValue, param1){});

 tapable.plugin('eventname', function(processValue, param1){});

 var result = tapable.applyPluginsWaterfall('eventname', defaultValue, param1);

applyPluginsWaterfall2使用說明:

源碼:

 

用法:

 var tapable = new Tapable();

 tapable.plugin('eventname', function(processValue, param1, param2){});

 tapable.plugin('eventname', function(processValue, param1, param2){});

 var result = tapable.applyPluginsWaterfall('eventname', defaultValue, param1, param2);

小結:applyPluginsWaterfall系列觸發的事件在參數中須要傳入默認值(須要被加工的數據),在監聽函數處理完後,須要獲取默認值被處理完後的結果。

3.1.3 applyPluginsBailResult、applyPluginsBailResult一、applyPluginsBailResult二、applyPluginsBailResult三、applyPluginsBailResult四、applyPluginsBailResult5

 這個系列的觸發函數須要有返回值,它還有一個特殊之處在監聽函數有返回值的狀況下,會提早返回。僅以applyPluginsBailResult爲例,其餘幾個方法只是參數不一樣而已。

源碼:

用法:

 

小結:從執行結果能夠看出第二個監聽函數返回告終果後,第三次監聽就沒有執行。最終的返回結果是第二次監聽的結果。

3.1.4 applyPluginsAsyncSeries、applyPluginsAsync、applyPluginsAsyncSeries1

僅以applyPluginsAsync爲例進行分析

 源碼:

用法:

 

小結:從源碼和執行結果上看,這組方法的做用是模仿異步的工做流程,在一個監聽執行完後,在這個監聽的回調函數裏面去執行下一個監聽函數,相似異步流程。

3.1.5 applyPluginsAsyncSeriesBailResult、applyPluginsAsyncSeriesBailResult1

 以applyPluginsAsyncSeriesBailResult爲例進行分析

源碼:

用法:

 

從源碼和執行結果上分析,applyPluginsAsyncSeriesBailResult函數時以異步的方式進行調用監聽函數,但能夠提早返回(監聽函數的回調函數中有參數)。

3.1.6 applyPluginsAsyncWaterfall

 源碼:

用法:

 

小結:applyPluginsAsyncWaterfall方法是以異步的方式串聯起監聽函數,每一個監聽函數將前一個函數的處理結果做爲參數繼續處理,監聽函數的整個執行過程就像流水線同樣運做。

3.1.7 applyPluginsParallel

 源碼:

用法:

 

小結:從源碼和運行結果來看,applyPluginsParallel方法觸發的方法是並行執行的,三個監聽函數最後調用的callback函數(這個callback指的是觸發函數執行的回調)與代碼的編寫順序無關,與實際結束的時間相關。三個監聽函數,最後執行的纔會調用觸發函數中的回調函數。

3.1.8 applyPluginsParallelBailResult、applyPluginsParallelBailResult1

源碼:

用法:

小結:從源碼和執行結果分析,applyPluginsParallelBailResult觸發的方法是並行執行,與applyPluginsParallel不一樣的是,觸發函數的回調能夠提早執行(沒必要等全部的監聽函數執行完畢)。

 總結

apply方法用來註冊插件。

plugin用來監聽具體事件。

applyPlugins、applyPlugins0、applyPlugins一、applyPlugins2;applyPluginsWaterfall、applyPluginsWaterfall0、applyPluginsWaterfall一、applyPluginsWaterfall2;applyPluginsBailResult、applyPluginsBailResult一、applyPluginsBailResult二、applyPluginsBailResult三、applyPluginsBailResult四、applyPluginsBailResult5;applyPluginsAsyncSeries、applyPluginsAsync、applyPluginsAsyncSeries1;applyPluginsAsyncSeriesBailResult、applyPluginsAsyncSeriesBailResult1;applyPluginsAsyncWaterfall;applyPluginsParallel;applyPluginsParallelBailResult、applyPluginsParallelBailResult1 這些方法用來觸發具體事件

觸發函數的區別以下表所示:

方法名 監聽函數的回調函數的最後一個參數是不是函數 監聽函數執行方式 觸發函數是否有返回值 觸發函數的參數中是否有回調函數 觸發函數的回調函數可否提早執行
applyPlugins 不涉及 不涉及
applyPluginsWaterfall 不涉及 不涉及
applyPluginsBailResult 不涉及 不涉及
applyPluginsAsyncSeries 異步 監聽函數正常執行不會提早執行
applyPluginsAsyncSeriesBailResult 異步 能夠
applyPluginsAsyncWaterfall 異步 監聽函數正常執行不會提早執行
applyPluginsParallel 同步 監聽函數正常執行不會提早執行
applyPluginsParallelBailResult 同步 能夠

說明:

監聽函數指的是:plugin函數

監聽函數的回調函數指的是(標紅的函數):plugin('eventname', callbackfn())

觸發函數指的是:applyPlugins等函數

觸發函數的回調函數指的是(標紅的函數):tapable.applyPluginsAsync('eventname', params, function(){})

相關文章
相關標籤/搜索