热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Webpack源码(一)——Tapable和事宜流

1、TapableTap的英文单词诠释,除了最经常运用的点击手势以外,另有一个意义是水龙头——在webpack中指的是后一种;Webpack能够认为是一种基于事宜流的编程范例,内部

1、Tapable

Tap 的英文单词诠释,除了最经常运用的 点击 手势以外,另有一个意义是 水龙头 —— 在 webpack 中指的是后一种;

Webpack 能够认为是一种基于事宜流的编程范例,内部的事情流程都是基于 插件 机制串接起来;

而将这些插件粘合起来的就是webpack本身写的基础类 Tapable 是,plugin要领就是该类暴露出来的;

背面我们将看到中心的对象 Compiler、Compilation 等都是继承于该对象

基于该类范例而其的 Webpack 体系保证了插件的有序性,使得全部体系异常有弹性,扩展性很好;但是有一个致命的瑕玷就是调试、看源码真是很痛楚,种种跳来跳去;(基于事宜流的写法,和程序语言中的 goto 语句很类似)

把这个堆栈下载,运用 Webstorm 举行调试,test 目次是很好的教程进口;

Tapable.plugin():相称于把对象归类到名为 name 的对象下,以array的情势;一切的插件都存在私有变量 _plugin 变量中;

《Webpack 源码(一)—— Tapable 和 事宜流》

接下来我们简朴节选几个函数剖析一下:

1.1、apply 要领

该要领最一般也是最经常运用的,看一下它的定义:


Tapable.prototype.apply = function apply() {
for(var i = 0; i arguments[i].apply(this);
}
};

毫无牵挂,就是 挨个递次 实行传入到该函数要领中对象的 apply 要领;一般传入该函数的对象也是 Tapable 插件 对象,因而必定也存在 apply 要领;(Webpack 的插件就是Tapable对象,因而必需要供应 apply 要领 )

只是变动上下文为当前 this

因而当前这里最大的作用就是传入当前 Tapable 的上下文

1.2、 applyPluginsAsync(name,…other,callback)

// 模仿两个插件
var _plugins = {
"emit":[
function(a,b,cb){
setTimeout(()=>{
console.log('1',a,b);
cb();
},1000);
},
function(a,b,cb){
setTimeout(()=>{
console.log('2',a,b);
cb();
},500)
}
]
}
applyPluginsAsync("emit",'#a','bbbbb',function(){console.log('end')});
// 输出效果:
// 1 #a bbbbb
// 2 #a bbbbb
// end

我们看到,虽然第一个插件是延后 1000ms 实行,第二个则是延后 500ms,但在真正实行的时刻,是严厉根据递次实行的;每一个插件须要在末了显式挪用cb()关照下一个插件的运转;

这里须要注重每一个插件的形参的个数都要一致,且末了一个必需是cb()要领,用于唤起下一个插件的运转;cb的第一个参数是err,假如该参数不为空,就直接挪用末了callback,中缀后续插件的运转;

1.3、 applyPluginsParallel(name,…other,callback)

大部分代码和
applyPluginsAsync 有点儿类似

这个 applyPluginsParallel 主要功用和 最简朴的 applyPlugins 要领比较类似,无论怎样都邑让一切注册的插件运转一遍

只是比拟 applyPlugins 多了一个分外的功用,它末了 供应一个 callback 函数,这个 callback 的函数比较顽强,假如一切的插件x都一般实行,且末了都cb(),则会在末了实行callback里的逻辑;不过,一旦个中某个插件运转失足,就会挪用这个callback(err),以后就算插件有毛病也不会再挪用该callback函数;


var _plugins = {
"emit":[
function(a,b,cb){
setTimeout(()=>{
console.log('1',a,b);
cb(null,'e222','33333');
},1000);
},
function(a,b,cb){
setTimeout(()=>{
console.log('2',a,b);
cb(null,'err');
},500)
}
]
}
applyPluginsParallel("emit",'#a','bbbbb',function(a,b){console.log('end',a,b)});
// 输出效果:
// 2 #a bbbbb
// 1 #a bbbbb
// end undefined undefined

上面的两个插件都是挪用了 cb,且第一个参数是 null(示意没有毛病),所以末了能输出 callback 函数中的 console 内容;

假如解释两个插件中任何一个 cb() 挪用,你会发明末了的 callback 没有实行

假如让 第二个 cb()的第一个值不是 null,比方 cb(‘err’),则 callback 以后输出这个毛病,以后再也不会挪用此 callback:

var _plugins = {
"emit":[
function(a,b,cb){
setTimeout(()=>{
console.log('1',a,b);
cb('e222','33333');
},1000);
},
function(a,b,cb){
setTimeout(()=>{
console.log('2',a,b);
cb('err');
},500)
}
]
}
// 输出效果:
// 2 #a bbbbb
// end err undefined
// 1 #a bbbbb

1.4、 applyPluginsWaterfall(name, init, callback)

望文生义,这个要领相称因而 瀑布式 挪用,给第一个插件传入初始对象 init,然后经由第一个插件挪用以后会取得一个效果对象,该效果对象会传给下一个插件 作为初始值,直到末了挪用终了,末了一个插件的直接效果传给 callback 作为初始值;

1.5、 applyPluginsParallelBailResult(name,…other,callback)

这个要领应该是一切要领中最难明白的;

起首它的行动和 applyPluginsParallel 异常类似,起首会 无论怎样都邑让一切注册的插件运转一遍(根据注册的递次)

为了让 callback 实行,其前提条件是每一个插件都须要挪用 cb();

但个中的 callback 只会实行一次(当传给cb的值不是undefined/null 的时刻),这一次实行递次是插件定义递次有关,而跟每一个插件中的 cb() 实行时间无关的


var _plugins = {
"emit":[
function(a,b,cb){
setTimeout(()=>{
console.log('1',a,b);
cb();
},1000);
},
function(a,b,cb){
setTimeout(()=>{
console.log('2',a,b);
cb();
},500)
},
function(a,b,cb){
setTimeout(()=>{
console.log('3',a,b);
cb();
},1500)
}
]
}
applyPluginsParallelBailResult("emit",'#a','bbbbb',function(a,b){console.log('end',a,b)});
// 运转效果
// 2 #a bbbbb
// 1 #a bbbbb
// 3 #a bbbbb
// end undefined undefined

这是最一般的运转状况,我们轻微调解一下(注重三个插件运转的递次2-1-3),分别给cb传入有用的值:


var _plugins = {
"emit":[
function(a,b,cb){
setTimeout(()=>{
console.log('1',a,b);
cb('1');
},1000);
},
function(a,b,cb){
setTimeout(()=>{
console.log('2',a,b);
cb('2');
},500)
},
function(a,b,cb){
setTimeout(()=>{
console.log('3',a,b);
cb('3');
},1500)
}
]
}
applyPluginsParallelBailResult("emit",'#a','bbbbb',function(a,b){console.log('end',a,b)});
// 运转效果
// 2 #a bbbbb
// 1 #a bbbbb
// end 1 undefined
// 3 #a bbbbb

能够发明第1个插件 cb('1') 实行了,后续的 cb('2')cb('3') 都给疏忽了;

这是由于插件注册递次是 1-2-3,虽然运转的时刻递次是 2-1-3,但所运转的照样 1 对应的 cb;所以,就算1实行的速率最慢(比方把其setTimeout的值设置成 2000),运转的 cb 仍然是1对应的cb;

个中触及的魔法是
闭包,传入的
i就是和注册递次绑定了

如许一申明,你会发明 applyPluginsParallel 的 cb 实行机遇是和实行时间有关联的,你能够本身考证一下;

1.6、总结

总结一下,Tapable 就相称因而一个 事宜管家,它所供应的 plugin 要领类似于 addEventListen 监听事宜,apply 要领类似于事宜触发函数 trigger

《Webpack 源码(一)—— Tapable 和 事宜流》


推荐阅读
author-avatar
一月的泰迪熊
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有