FE.SRC-webpack/tapable-0.2 原始碼分析

seasonley發表於2019-02-16

Tapable

https://github.com/webpack/ta…
https://segmentfault.com/a/11…

var Tapable = require("tapable");

Tapable 是一個用於外掛繫結的類

繼承方式1

function MyClass() {
    Tapable.call(this);
}

MyClass.prototype = Object.create(Tapable.prototype);

MyClass.prototype.method = function() {};

繼承方式2

function MyClass2() {
    EventEmitter.call(this);
    Tapable.call(this);
}

MyClass2.prototype = Object.create(EventEmitter.prototype);
Tapable.mixin(MyClass2.prototype);

MyClass2.prototype.method = function() {};

公有方法

apply

void apply(plugins: Plugin...)

通過呼叫apply它們將作為引數傳遞的所有外掛附加到例項。

plugin

void plugin(names: string|string[], handler: Function)

names需要監聽的事件名稱,可以傳入事件名稱集合(同時繫結多個事件),也可以傳入單個事件名稱
handler 事件的處理函式

私有方法

applyPlugins

void applyPlugins(name: string, args: any...)

同步呼叫所有的name外掛,傳入引數args,並行的呼叫所有註冊在事件name上的處理函式。所有註冊的處理方法並行執行,相互獨立互不干擾。(根據傳參格式內部提供了applyPlugins0,applyPlugins1,applyPlugins2)

function applyPlugins1(name, param) {
    var plugins = this._plugins[name];
    if(!plugins) return;
    for(var i = 0; i < plugins.length; i++)
        plugins[i].call(this, param);
};

applyPluginsWaterfall

any applyPluginsWaterfall(name: string, init: any, args: any...)

序列的呼叫所有的name外掛,
第一個處理函式傳入init和args,
後續的處理函式傳入前一個處理函式的返回值和args,
最終返回最後一個處理函式的返回結果
(內部同樣提供了012方法)

function applyPluginsWaterfall1(name, init, param) {
    var plugins = this._plugins[name];
    if(!plugins) return init;
    var current = init;
    for(var i = 0; i < plugins.length; i++)
        current = plugins[i].call(this, current, param);
    return current;
};

applyPluginsAsync | applyPluginsAsyncSeries

void applyPluginsAsync(
    name: string,
    args: any...,
    callback: (err?: Error) -> void
)

非同步呼叫所有的name外掛(依次執行),倘若某一個處理函式報錯,則執行傳入的callback(err),後續的處理函式將不被執行,否則最後一個處理函式呼叫callback

function applyPluginsAsyncSeries1(name, param, callback) {
    var plugins = this._plugins[name];
    if(!plugins || plugins.length === 0) return callback();
    var i = 0;
    var _this = this;
    var innerCallback = copyProperties(callback, function next(err) {
        if(err) return callback(err);
        i++;
        if(i >= plugins.length) {
            return callback();
        }
        plugins[i].call(_this, param, innerCallback);
    });
    plugins[0].call(this, param, innerCallback);
};

applyPluginsBailResult

any applyPluginsBailResult(name: string, args: any...)

同步呼叫所有的name外掛,如果其中一個處理函式返回值!== undefined,直接返回這個返回值,後續的處理函式將不被執行

function applyPluginsBailResult1(name, param) {
    if(!this._plugins[name]) return;
    var plugins = this._plugins[name];
    for(var i = 0; i < plugins.length; i++) {
        var result = plugins[i].call(this, param);
        if(typeof result !== "undefined") {
            return result;
        }
    }
};

applyPluginsAsyncWaterfall

applyPluginsAsyncWaterfall(
    name: string,
    init: any,
    callback: (err: Error, result: any) -> void
)

非同步呼叫所有的name外掛。後續的函式依賴於前一個函式執行回撥的時候傳入的引數nextValue(第一個處理函式傳入引數init)。
倘若某一個處理函式報錯,則執行傳入的callback(err),後續的處理函式將不被執行,否則最後一個處理函式呼叫callback(value)。

function applyPluginsAsyncWaterfall(name, init, callback) {
    if(!this._plugins[name] || this._plugins[name].length === 0) return callback(null, init);
    var plugins = this._plugins[name];
    var i = 0;
    var _this = this;
    var next = copyProperties(callback, function(err, value) {
        if(err) return callback(err);
        i++;
        if(i >= plugins.length) {
            return callback(null, value);
        }
        plugins[i].call(_this, value, next);
    });
    plugins[0].call(this, init, next);
};

applyPluginsParallel

applyPluginsParallel(
    name: string,
    args: any...,
    callback: (err?: Error) -> void
)

並行的呼叫所有註冊在事件name上的處理函式,倘若任一處理函式執行報錯,則執行callback(`err`),否則當所有的處理函式都執行完的時候呼叫callback()

function applyPluginsParallel(name) {
    var args = Array.prototype.slice.call(arguments, 1);
    var callback = args.pop();
    if(!this._plugins[name] || this._plugins[name].length === 0) return callback();
    var plugins = this._plugins[name];
    var remaining = plugins.length;
    args.push(copyProperties(callback, function(err) {
        if(remaining < 0) return; // ignore
        if(err) {
            remaining = -1;
            return callback(err);
        }
        remaining--;
        if(remaining === 0) {
            return callback();
        }
    }));
    for(var i = 0; i < plugins.length; i++) {
        plugins[i].apply(this, args);
        if(remaining < 0) return;
    }
};

applyPluginsParallelBailResult

applyPluginsParallelBailResult(
    name: string,
    args: any...,
    callback: (err: Error, result: any) -> void
)

並行呼叫,每個處理函式必須呼叫callback(err, result),
倘若任一處理函式在呼叫callback(err, result)的時候,err!==undefined || result!==undefined,則callback將真正被執行,後續的處理函式則不會再被執行。
順序由註冊外掛順序決定,而不是由函式的執行時間。

applyPluginsParallelBailResult1(name, param, callback) {
    var plugins = this._plugins[name];
    if(!plugins || plugins.length === 0) return callback();
    var currentPos = plugins.length;
    var currentResult;
    var done = [];
    for(var i = 0; i < plugins.length; i++) {
        var innerCallback = (function(i) {
            return copyProperties(callback, function() {
                if(i >= currentPos) return; // ignore
                done.push(i);
                if(arguments.length > 0) {
                    currentPos = i + 1;
                    done = fastFilter.call(done, function(item) {
                        return item <= i;
                    });
                    currentResult = Array.prototype.slice.call(arguments);
                }
                if(done.length === currentPos) {
                    callback.apply(null, currentResult);
                    currentPos = 0;
                }
            });
        }(i));
        plugins[i].call(this, param, innerCallback);
    }
};

hasPlugins

hasPlugins(
    name: string
)

如果為此名稱註冊了外掛,則返回true。

相關文章