express源码剖析1
什么是中间件?
1.EventEmitter.prototype
- mixin(app, EventEmitter.prototype, false);
app为一个函数,也是对象,mixin是一个类库(merge-descriptors)。它就是一种mixin设计模式,作用是让app这个对象具有EventEmitter.prototype的方法。第三个参数表示“是否重新定义app中与EventEmitter.prototype中存在重名的方法。
EventEmitter类是nodejs中event的一个类,也是唯一类。它的核心是对事件触发与事件监听功能的封装。
EventEmitter实例的产生?
大多数 Node.js 核心 API 都是采用惯用的异步事件驱动架构,其中某些类型的对象(称为触发器)会周期性地触发命名事件来调用函数对象(监听器)。
Node.js里面的许多对象都会分发事件:一个net.Server对象(创建TCP或本地服务器)会在每次有新连接时分发一个事件, 一个fs.readStream对象会在文件被打开的时候发出一个事件。 所有这些产生事件的对象都是 events.EventEmitter 的实例。
EventEmitter类的使用
1.1 newListener事件
当注册一个事件时,触发newListener事件,例如:
- var MyEmitter = require("events");
- const myEmitter = new MyEmitter();
- // Only do this once so we don't loop forever
- //当新的监听器被添加时,所有的 EventEmitter 会触发 'newListener' 事件;
- //当移除已存在的监听器时,则触发 'removeListener'。
- myEmitter.once('newListener', (event, listener) => {
- if (event === 'event') {
- // Insert a new listener in front
- myEmitter.on('event', () => {
- console.log('B');
- });
- }
- });
- myEmitter.on('event', () => {
- console.log('A');
- });
- myEmitter.emit('event');
- //B
- //A
1.2 EventEmitter.defaultMaxListeners
唯一的静态成员,默认值是10,表示对应监听同一的事件个数是10个,不建议修改这个参数,否则会影响到所有EventEmitter实例的。
1.3 EventEmitter的prototype对象
- var MyEmitter = require('events');
- console.log(MyEmitter.prototype);
//结果是:
EventEmitter {
- domain: undefined,
- _events: undefined,
- _maxListeners: undefined,
- setMaxListeners: [Function: setMaxListeners],
- getMaxListeners: [Function: getMaxListeners],
- emit: [Function: emit],
- addListener: [Function: addListener],
- on: [Function: addListener],
- once: [Function: once],
- removeListener: [Function: removeListener],
- removeAllListeners: [Function: removeAllListeners],
- listeners: [Function: listeners],
- listenerCount: [Function: listenerCount] }
- [Finished in 0.3s]
app对象(函数)它具有以上方法,即app继承了EventEmitter的原型对象,值得注意的是:大部分模块继承自Event模块。
在express中的应用中,app对象通过on绑定了mount事件,如下:
- //这个函数的重点是parent参数
- this.on('mount', function onmount(parent) {
- // inherit trust proxy
- if (this.settings[trustProxyDefaultSymbol] === true
- //parent.settings['trust proxy fn'] = compileTrust(val)
- && typeof parent.settings['trust proxy fn'] === 'function') {
- delete this.settings['trust proxy'];
- delete this.settings['trust proxy fn'];
- }
- // inherit protos
- this.request.__proto__ = parent.request;
- this.response.__proto__ = parent.response;
- this.engines.__proto__ = parent.engines;
- this.settings.__proto__ = parent.settings;
- });
下面是利用到的中间件
array-flatten
有一个函数flattern,它的作用是把数组从多维变成一维,例如:
- var flatten = require('array-flatten');
- var arr = [1,2,5,[1,3]];
- console.log(flatten(arr));
- //[1,2,5,1,3]
finalhandler
finalhandler的作用就是一个http请求的最后一步的处理方式,
- var finalhandler = require('finalhandler');
- /*从handler传递过来的callback为undefined,
- finalhandler返回一个函数,这个函数可以出发done(err),
- 如果err为false,它将在res写入404,否则,会在res中写入错误信息。
- */
- var done = callback || finalhandler(req, res, {
- env: this.get('env'),
- onerror: logerror.bind(this)
- });
parseUrl
var req1 = {
url: "http://localhost:4000/m/xx/login.html?kf=33",
};
var str = parseUrl(req1);
console.log("str=",str);
//str= Url {
protocol: 'http:',
slashes: true,
auth: null,
host: 'localhost:4000',
port: '4000',
hostname: 'localhost',
hash: null,
search: '?kf=33',
query: 'kf=33',
pathname: '/m/xx/login.html',
path: '/m/xx/login.html?kf=33',
href: 'http://localhost:4000/m/xx/login.html?kf=33',
_raw: 'http://localhost:4000/m/xx/login.html?kf=33' }
类似url包中parse方法
- var url = require('url');
- var testStr = "http://www.sina.com//xx/y/z.html?ss=1&s=2";
- //第二个参数为false,返回对象中query为字符串。第三个参数看文档测试没什么鸟用
- console.log(url.parse(testStr,false,true));
- console.log(url.parse(testStr,true,true));
- console.log(url.parse(testStr,true,false));
- /*
- Url {
- protocol: 'http:',
- slashes: true,
- auth: null,
- host: 'www.sina.com',
- port: null,
- hostname: 'www.sina.com',
- hash: null,
- search: '?ss=1&s=2',
- query: 'ss=1&s=2',
- pathname: '//xx/y/z.html',
- path: '//xx/y/z.html?ss=1&s=2',
- href: 'http://www.sina.com//xx/y/z.html?ss=1&s=2' }
- Url {
- protocol: 'http:',
- slashes: true,
- auth: null,
- host: 'www.sina.com',
- port: null,
- hostname: 'www.sina.com',
- hash: null,
- search: '?ss=1&s=2',
- query: { ss: '1', s: '2' },
- pathname: '//xx/y/z.html',
- path: '//xx/y/z.html?ss=1&s=2',
- href: 'http://www.sina.com//xx/y/z.html?ss=1&s=2' }
- Url {
- protocol: 'http:',
- slashes: true,
- auth: null,
- host: 'www.sina.com',
- port: null,
- hostname: 'www.sina.com',
- hash: null,
- search: '?ss=1&s=2',
- query: { ss: '1', s: '2' },
- pathname: '//xx/y/z.html',
- path: '//xx/y/z.html?ss=1&s=2',
- href: 'http://www.sina.com//xx/y/z.html?ss=1&s=2' }
- */
pathRegexp
在Layer.js中利用到。path-to-regexp是express的路由规则,初始化pathRegexp有三个参数:path(可以是正则表达式),key(对path中关键字填充的数组)和options,options包括三个参数,
分别是end,caseSensitive和strict,具体可以参考http://blog.csdn.net/chszs/article/details/51055229。
- var pathRegexp = require('path-to-regexp');
- /*
- var layer = Layer('/', {}, handle);
- this.keys是对path中参数的一种解释。如path="/user/:foo",那么keys= [name:"foo",delimiter:"false"]
- */
- this.regexp = pathRegexp(path, this.keys = [], opts);
- // end为false时,正则从path开始进行匹配,相当于^
- if (path === '/' && opts.end === false) {
- this.regexp.fast_slash = true;
- }
看下面一个例子:
- function test(){
- var keys = [],
- opts= {
- "sensitive":false,
- "strict":false,
- "end":false
- },
- regexp = pathRegexp("/user/:id/:page/", keys = [], opts);
- var m = regexp.exec("/user/anthonyliu/your");
- console.log("m="+JSON.stringify(m));
- }
- test();
- //第一个元素是输入的路径,后面都是匹配的分组!
- //m=["/user/anthonyliu/your","anthonyliu","your"]
compileQueryParser
- var compileQueryParser = require('./utils').compileQueryParser;
- compileQueryParser("extended");
qs是express依赖的包
他只提供两个方法:parse,和stringify,qs.parse作为回调函数传递给middleware/query。query返回一个函数,给rounter.use调用。
- /*
- middlemare/query,返回该函数,给rounter.user
- */
- return function query(req, res, next){
- if (!req.query) {
- var val = parseUrl(req).query;
- req.query = queryparse(val, opts);
- }
- next();
- };
- };
express源码剖析1的更多相关文章
- express源码剖析2
当使用express时,代码会这样写: var express = require('express'); 如果创建一个express的应用,代码会这样写: var app = express(); ...
- express源码剖析--Router模块
1.加载模块执行代码: methods.forEach(function(method){ //method是http协议的各种请求方法,如:get,put,headee,post Route.pro ...
- Node 进阶:express 默认日志组件 morgan 从入门使用到源码剖析
本文摘录自个人总结<Nodejs学习笔记>,更多章节及更新,请访问 github主页地址.欢迎加群交流,群号 197339705. 章节概览 morgan是express默认的日志中间件, ...
- STL源码剖析——hashtable
二叉搜索树具有对数时间的搜索复杂度,但是这样的复杂度是再输入数据有足够的随机性的假设上哈希表在插入删除搜索操作上也具有常数时间的表现,而且这种表现是以统计为基础,不需要依赖输入元素的随机性 hasht ...
- jQuery之Deferred源码剖析
一.前言 大约在夏季,我们谈过ES6的Promise(详见here),其实在ES6前jQuery早就有了Promise,也就是我们所知道的Deferred对象,宗旨当然也和ES6的Promise一样, ...
- Nodejs事件引擎libuv源码剖析之:高效线程池(threadpool)的实现
声明:本文为原创博文,转载请注明出处. Nodejs编程是全异步的,这就意味着我们不必每次都阻塞等待该次操作的结果,而事件完成(就绪)时会主动回调通知我们.在网络编程中,一般都是基于Reactor线程 ...
- Apache Spark源码剖析
Apache Spark源码剖析(全面系统介绍Spark源码,提供分析源码的实用技巧和合理的阅读顺序,充分了解Spark的设计思想和运行机理) 许鹏 著 ISBN 978-7-121-25420- ...
- 基于mybatis-generator-core 1.3.5项目的修订版以及源码剖析
项目简单说明 mybatis-generator,是根据数据库表.字段反向生成实体类等代码文件.我在国庆时候,没事剖析了mybatis-generator-core源码,写了相当详细的中文注释,可以去 ...
- STL"源码"剖析-重点知识总结
STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1.STL概述 STL提供六大组件,彼此可以组合 ...
随机推荐
- Android 开源库和项目 2
1.带尾巴的RecyclerViewPager 特点:1.像viewPager一样滑动一次就滑动一页 2.像画廊gallery一样,滑动一次可以滑动很多页 3.竖向滑动 4.支持点击事件,没有错乱 ...
- 一种面向对象的TCP/IP中间件
这是一个使用C++封装的TCP/IP协议栈(仅传输层),属于本人所设计的中间件的一员,具有硬件无关,应用无关特性,使用非常方便,一看代码便知: #include "net.h" / ...
- iOS总结:项目中的各种小坑汇总
一.字符串转JSON 在网络请求时,如果服务端返回的是字符串,那么就需要我们自己封装一个类,将请求下来的字符串转换成json对象,从而存入模型中. 注意: 字符串中如果含有一些特殊转意符(如\n.\t ...
- iOS开发常用代码块(第二弹)
GCD定时器 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ); dispat ...
- 超像素经典算法SLIC的代码的深度优化和分析。
现在这个社会发展的太快,到处都充斥着各种各样的资源,各种开源的平台,如github,codeproject,pudn等等,加上一些大型的官方的开源软件,基本上能找到各个类型的代码.很多初创业的老板可能 ...
- [No0000A7]批处理经常用到的变量及批处理>NUL详细介绍
绝对路径是指调用绝对的程序位置的路径,例如: start C:\Windows\test.exe 相对路径是文件改变路径以后还会按照变量的路径所在位置去调用,例如: start %WINDIR%\te ...
- Spring 框架的架包分析、功能作用、优点,及jar架包简介
Spring 框架的架包详解 Spring的作用 Spring的优势 由于刚搭建完一个MVC框架,决定分享一下我搭建过程中学习到的一些东西.我觉得不管你是个初级程序员还是高级程序员抑或 ...
- 【repost】JavaScript完美运动框架的进阶之旅
运动框架的实现思路 运动,其实就是在一段时间内改变left.right.width.height.opactiy的值,到达目的地之后停止. 现在按照以下步骤来进行我们的运动框架的封装: 匀速运动. 缓 ...
- 1366分辨率其实是1368分辨率,firefox a标签点击有虚线
1,通过intel 集成显卡的软件自定义一个1366分辨率,发现是1368的分辨率,@media screen and (max-deivce-width:1368px)才有效果,并且在同事电脑默认分 ...
- node基础12:动态网页
1.显示动态网页 又到了激动人心的时刻,马上就可以使用node创建动态网站了,其原理为: 在HTML模板中使用占位符 根据请求路径,确定需要返回的页面 根据请求参数来确定静态模板中占位符的值 使用正则 ...