资讯专栏INFORMATION COLUMN

FE.SRC-webpack/tapable-0.2 源码分析

luckyyulin / 3018人阅读

摘要:所有注册的处理方法并行执行,相互独立互不干扰。倘若某一个处理函数报错,则执行传入的,后续的处理函数将不被执行,否则最后一个处理函数调用。顺序由注册插件顺序决定,而不是由函数的执行时间。如果为此名称注册了插件,则返回。

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。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/108639.html

相关文章

  • 源码之下无秘密 ── 做最好的 Netty 源码分析教程

    摘要:背景在工作中虽然我经常使用到库但是很多时候对的一些概念还是处于知其然不知其所以然的状态因此就萌生了学习源码的想法刚开始看源码的时候自然是比较痛苦的主要原因有两个第一网上没有找到让我满意的详尽的源码分析的教程第二我也是第一次系统地学习这么大代 背景 在工作中, 虽然我经常使用到 Netty 库, 但是很多时候对 Netty 的一些概念还是处于知其然, 不知其所以然的状态, 因此就萌生了学...

    shenhualong 评论0 收藏0
  • Spring IOC 容器源码分析 - 余下的初始化工作

    摘要:简介本篇文章是容器源码分析系列文章的最后一篇文章,本篇文章所分析的对象是方法,该方法用于对已完成属性填充的做最后的初始化工作。后置处理器是拓展点之一,通过实现后置处理器接口,我们就可以插手的初始化过程。 1. 简介 本篇文章是Spring IOC 容器源码分析系列文章的最后一篇文章,本篇文章所分析的对象是 initializeBean 方法,该方法用于对已完成属性填充的 bean 做最...

    Alfred 评论0 收藏0
  • 系列文章目录

    摘要:为了避免一篇文章的篇幅过长,于是一些比较大的主题就都分成几篇来讲了,这篇文章是笔者所有文章的目录,将会持续更新,以给大家一个查看系列文章的入口。 前言 大家好,笔者是今年才开始写博客的,写作的初衷主要是想记录和分享自己的学习经历。因为写作的时候发现,为了弄懂一个知识,不得不先去了解另外一些知识,这样以来,为了说明一个问题,就要把一系列知识都了解一遍,写出来的文章就特别长。 为了避免一篇...

    lijy91 评论0 收藏0
  • 系列文章目录

    摘要:为了避免一篇文章的篇幅过长,于是一些比较大的主题就都分成几篇来讲了,这篇文章是笔者所有文章的目录,将会持续更新,以给大家一个查看系列文章的入口。 前言 大家好,笔者是今年才开始写博客的,写作的初衷主要是想记录和分享自己的学习经历。因为写作的时候发现,为了弄懂一个知识,不得不先去了解另外一些知识,这样以来,为了说明一个问题,就要把一系列知识都了解一遍,写出来的文章就特别长。 为了避免一篇...

    Yumenokanata 评论0 收藏0
  • 深入理解 WKWebView(入门篇)—— WebKit 源码调试与分析

    摘要:虽然苹果官方提供了关于的与使用说明,但这并不能满足开发者们的需求,各类复杂场景依旧让我们焦头烂额,而解决方案却不易寻找。二源码下载编译及调试之前我们首先需要获取一份苹果官方的源码。 一、前言移动互联网时代,网页依旧是内容展示的重要媒介,这离不开 WebKit 浏览内核技术的支持与发展。在 iOS 平台下开发者们...

    funnyZhang 评论0 收藏0

发表评论

0条评论

luckyyulin

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<