这一节继续深入Router模块,首先从最常用的use开始。

router.use

  方法源码如下:

proto.use = function use(fn) {
var offset = 0;
var path = '/'; if (typeof fn !== 'function') {
var arg = fn;
while (Array.isArray(arg) && arg.length !== 0) arg = arg[0];
if (typeof arg !== 'function') {
offset = 1;
path = fn;
}
} var callbacks = flatten(slice.call(arguments, offset)); if (callbacks.length === 0) throw new TypeError('Router.use() requires a middleware function') for (var i = 0; i < callbacks.length; i++) {
var fn = callbacks[i]; if (typeof fn !== 'function') throw new TypeError('Router.use() requires a middleware function but got a ' + gettype(fn)) debug('use %o %s', path, fn.name || '<anonymous>');
// 内部模块layer!
var layer = new Layer(path, {
sensitive: this.caseSensitive,
strict: false,
end: false
}, fn);
// 通过use方法生成的layer没有route值
layer.route = undefined;
// 初始化时定义的数组
this.stack.push(layer);
} return this;
};

  前半部分十分熟悉,根本就是app.use的翻版。

  当然,最后遍历中间件函数处理的时候就不一样了,引入了新的本地模块Layer。

Layer

  不太理解这个层的意义,无论是app.use还是router.use,每一个中间件都会生成一个layer对象,然后push进router上的stack数组。

  那么多路径呢,是否会生成多个layer?答案是否。

  看一眼layer的构造函数:

function Layer(path, options, fn) {
if (!(this instanceof Layer)) {
return new Layer(path, options, fn);
} debug('new %o', path)
var opts = options || {};
/**
* layer.handle => 中间件函数
* layer.name => 函数名
* layer.regexp => 路径的正则
*/
this.handle = fn;
this.name = fn.name || '<anonymous>';
this.params = undefined;
this.path = undefined;
this.regexp = pathRegexp(path, this.keys = [], opts); // 快速匹配标记
this.regexp.fast_star = path === '*'
this.regexp.fast_slash = path === '/' && opts.end === false
}

  其中比较关键一步是根据传进来的path生成一个正则,pathRegexp是一个工具模块,无论传进去的是字符串、数组、正则都能返回一个正则匹配需要的值。

  简略的看一下工具核心源码:

function pathtoRegexp(path, keys, options) {
// ... // 字符串
path = ('^' + path + (strict ? '' : path[path.length - 1] === '/' ? '?' : '/?'));
// ...后面有很多replace // 数组
if (Array.isArray(path)) {
path = path.map(function(value) {
return pathtoRegexp(value, keys, options).source;
});
// 使用|分割多个规则来进行多重匹配
return new RegExp('(?:' + path.join('|') + ')', flags);
} // 正则 比较简单的
// var MATCHING_GROUP_REGEXP = /\((?!\?)/g;
if (path instanceof RegExp) {
// 匹配组
while (m = MATCHING_GROUP_REGEXP.exec(path.source)) {
keys.push({
name: name++,
optional: false,
offset: m.index
});
} return path;
}
}

  字符串模式非常复杂,因为允许类正则写法的字符串,解析会变得十分复杂,后面有很多很多的replace,这里给一个开头,比较简单过把瘾。

  最后返回一个匹配路径的正则表达式,然后在该对象上加两个标记,比如说如果一个Layer的正则对象有全局路由标记,则根本不用正则校验,直接可以调用中间件。

  返回Layer对象后,该对象会被push进router的stack数组。

  

  这节就简单过一下Router模块的use方法,下一节看看具体请求方法的源码流向。

.6-浅析express源码之Router模块(2)-router.use的更多相关文章

  1. .2-浅析express源码之applicaiton模块(1)-咸鱼方法

    上一节讲了express的入口文件,当执行主函数,会调用app.init方法,这个方法就来源于application模块. 这个模块有很多方法,目前仅仅过一下初始化方法: app.init = fun ...

  2. .3-浅析express源码之applicaiton模块(2)-app.render

    这个模块还漏了一个稍微复杂点的API,就是app.render,首先看官网的定义: app.render(view, [locals], callback) view为对应的文件名,locals为一个 ...

  3. .4-浅析express源码之applicaiton模块(3)-compile函数

    基本上application模块的api都看的差不多了,但是在app.set中还有一个遗漏点,如下: app.set = function set(setting, val) { // ...设值 / ...

  4. .5-浅析express源码之Router模块(1)-默认中间件

    模块application已经完结,开始讲Router路由部分. 切入口仍然在application模块中,方法就是那个随处可见的lazyrouter. 基本上除了初始化init方法,其余的app.u ...

  5. express源码分析之Router

    express作为nodejs平台下非常流行的web框架,相信大家都对其已经很熟悉了,对于express的使用这里不再多说,如有需要可以移步到www.expressjs.com自行查看express的 ...

  6. nginx源码分析之模块初始化

    在nginx启动过程中,模块的初始化是整个启动过程中的重要部分,而且了解了模块初始化的过程对应后面具体分析各个模块会有事半功倍的效果.在我看来,分析源码来了解模块的初始化是最直接不过的了,所以下面主要 ...

  7. 读Zepto源码之Event模块

    Event 模块是 Zepto 必备的模块之一,由于对 Event Api 不太熟,Event 对象也比较复杂,所以乍一看 Event 模块的源码,有点懵,细看下去,其实也不太复杂. 读Zepto源码 ...

  8. 读Zepto源码之Callbacks模块

    Callbacks 模块并不是必备的模块,其作用是管理回调函数,为 Defferred 模块提供支持,Defferred 模块又为 Ajax 模块的 promise 风格提供支持,接下来很快就会分析到 ...

  9. 读Zepto源码之Deferred模块

    Deferred 模块也不是必备的模块,但是 ajax 模块中,要用到 promise 风格,必需引入 Deferred 模块.Deferred 也用到了上一篇文章<读Zepto源码之Callb ...

  10. 读Zepto源码之Ajax模块

    Ajax 模块也是经常会用到的模块,Ajax 模块中包含了 jsonp 的现实,和 XMLHttpRequest 的封装. 读 Zepto 源码系列文章已经放到了github上,欢迎star: rea ...

随机推荐

  1. Oracle包被锁定的原因分析及解决方案

    http://blog.csdn.net/jojo52013145/article/details/7470812 在数据库的开发过程中,经常碰到包.存储过程.函数无法编译或编译时会导致PL/SQL ...

  2. 4.动态HTML处理和机器图像识别

    Selenium Selenium是一个Web的自动化测试工具,最初是为网站自动化测试而开发的,类型像我们玩游戏用的按键精灵,可以按指定的命令自动操作,不同是Selenium 可以直接运行在浏览器上, ...

  3. Android-Version Compatibility Issues (Gradle 2.14.1 requires Android Gradle plugin 2.1.3 (or newer)) but project is using

      当AndroidStudio加载工程Project的时候,出现以上错误❌,千万不要点击,否则就是更多其他的错误:   解决方案: 1.认真翻译错误: 2.分析问题发生的原因,然后看到了 ..... ...

  4. caffe 教程

    Caffe是一个清晰而高效的深度学习框架,本文详细介绍了caffe的优势.架构,网络定义.各层定义,Caffe的安装与配置,解读了Caffe实现的图像分类模型AlexNet,并演示了CIFAR-10在 ...

  5. openstack手动安装

    安装文档: https://github.com/yongluo2013/osf-openstack-training/blob/master/installation/openstack-iceho ...

  6. unity2D 船只型物体驱动的实现

    船只向前行驶的驱动力 假设在水中没有摩擦阻力,船只有惯性,船只可以转弯,按下前进键时船只会在力的作用下使得自身的物理运动方向变化到自身的前方方向,从而向前行进. 上图中 V:船当前物理速度 V1,V2 ...

  7. Android------------------RecyclerView学习

    一.多种布局的保存 1.Type->getItemViewType(int position) 2.RecylerView.Holder       : 定一个holder的内部类,里面保存一些 ...

  8. Poetry

    1. Absence to love is what wind is to fire. It extinguishes the small; It inflames the great. 2. It ...

  9. 游戏AI玩伴,是“神队友”还是“猪队友”?

    “一代英豪”暴雪迎来了自己的暴风雪. 2月13日,动视暴雪公布了2018年全年财报.财报显示,暴雪第四季度营业收入仅为28.4亿美元,低于华尔街分析师预期的30.4亿美元.在公布了财报业绩后,该公司又 ...

  10. <转>PHP中正则表达式函数

    PHP中的正则表达式函数 在PHP中有两套正则表达式函数库.一套是由PCRE(Perl Compatible Regular Expression)库提供的,基于传统型NFA.PCRE库使用和Perl ...