使用express时,代码会这样写:

var express = require('express');

创建一个express的应用,代码:

var app = express();

那么express()是什么?它执行createApplication()

//express.js
exports = module.exports =createApplication;
/**
* Create an express application.
*
* @return {Function}
* @api public
*/ function createApplication() {
var app = function(req, res, next) {
app.handle(req, res, next);
}; mixin(app, EventEmitter.prototype, false);
mixin(app, proto, false); app.request = { __proto__: req, app: app };
app.response = { __proto__: res, app: app };
app.init();
return app;
//执行的结果就是app是一个实例,它有私有成员对象:request和 response,同时继承Event模块中的EventEmitter的原型。
}

在express.js中,要区分下面两个包:

var Route = require('./router/route');
var Router = require('./router');
//对外都暴露Route和Router,他们两者有些不同,
//Router是Route的超集,两者的联系只在Router.route用到。调用Router.route会得到一个route,不过给Router.stack添加了一个Layer,
//该Layer通过Router的参数和route.dispatch和用户的path来定义的。
//route只有三个成员,stack数组(储存Layer对象),path(路由的路径)和method对象。
//其中stack数组与Router一样,同时两个对象的原型都有methods的和all的方法
exports.Route = Route;
exports.Router = Router;

express也继承了application.js中的方法。执行app.init();

app.init = function init() {
//给app类/对象赋值三个公用成员, 在初始的过程中,有一个成员变量很关键,就是router
this.cache = {};
this.engines = {};
this.settings = {};
// 初始化配置,在研究defaultConfiguration之前,抽象下app.set函数,它就是给setting赋值的函数,同时针对key = "etag" 和 query parser以及"trust proxy"进行特殊的的设置。
this.defaultConfiguration();
};

app还挂有很多方法,这些可以在express的api中的application的方法找到!其中最重要的方法是app.use,它用来构造路由所执行的函数的一个数据结构_router,express在执行过程中,会遍历这个结构。

1.1app.use方法

//use的使用
var express = require('express');
var app = express();
function handlerWrap(){
console.log("1");
}
app.use("/", handlerWrap); //路径/会调用hanlerWrap方法

 app.use源码

this.lazyrouter();
app.lazyrouter = function lazyrouter() {
//给a公有变量_router赋值,它是对象Router的实例。
if (!this._router) {
//实例化Router
this._router = new Router({
caseSensitive: this.enabled('case sensitive routing'), //false
strict: this.enabled('strict routing') //false
});
//router.use(path,fn); 为path建立layer,有多少个fn,就建立多少个Layer,然后把这个layer压入router.stack数组中。初始定义了两个Layer
this._router.use(query(this.get('query parser fn')));
//this.get('query parser fn')为一个函数:
this._router.use(middleware.init(this));
}
};
if (!fn || !fn.handle || !fn.set) {
//handlerWrap函数为handler、 set成员!,如果fn函数没有handle,或者set函数,调用router.use(path,fn)。也就是说那不是express的实例,大部分插件都会直接执行。
return router.use(path, fn); //rounter.use直接把该函数构造成一个Layer成员,实际上是给router.stack添加一个layer成员。
}
debug('.use app under %s', path);
fn.mountpath = path; //如果是express的对象,那么给express这个对象成员mountpath赋值为path(可能含有正则);
fn.parent = this; //fn变成子express对象,当前的express为父。
// restore .app property on req and res //执行use,封装了fn,
router.use(path, function mounted_app(req, res, next) {
var orig = req.app; //这里看的不太懂。
fn.handle(req, res, function (err) {
req.__proto__ = orig.request;
res.__proto__ = orig.response;
next(err);
});
});
// mounted an app
console.log("fn="+JSON.stringify(fn));
fn.emit('mount', this);
// 进入router/index.js中,执行proto.use()方法。
// 实际上是给router.stack添加一个layer成员,
  var layer = new Layer(path, {
    sensitive: this.caseSensitive,
    strict: false,
    end: false
  }, fn);
  layer.route = undefined; //给layer.route赋值undefined
this.stack.push(layer);

 

express源码剖析2的更多相关文章

  1. express源码剖析1

    在通读源码之前,先把一些比较难理解的代码吃透: 1.EventEmitter.prototype mixin(app, EventEmitter.prototype, false); app为一个函数 ...

  2. express源码剖析--Router模块

    1.加载模块执行代码: methods.forEach(function(method){ //method是http协议的各种请求方法,如:get,put,headee,post Route.pro ...

  3. Node 进阶:express 默认日志组件 morgan 从入门使用到源码剖析

    本文摘录自个人总结<Nodejs学习笔记>,更多章节及更新,请访问 github主页地址.欢迎加群交流,群号 197339705. 章节概览 morgan是express默认的日志中间件, ...

  4. STL源码剖析——hashtable

    二叉搜索树具有对数时间的搜索复杂度,但是这样的复杂度是再输入数据有足够的随机性的假设上哈希表在插入删除搜索操作上也具有常数时间的表现,而且这种表现是以统计为基础,不需要依赖输入元素的随机性 hasht ...

  5. jQuery之Deferred源码剖析

    一.前言 大约在夏季,我们谈过ES6的Promise(详见here),其实在ES6前jQuery早就有了Promise,也就是我们所知道的Deferred对象,宗旨当然也和ES6的Promise一样, ...

  6. Nodejs事件引擎libuv源码剖析之:高效线程池(threadpool)的实现

    声明:本文为原创博文,转载请注明出处. Nodejs编程是全异步的,这就意味着我们不必每次都阻塞等待该次操作的结果,而事件完成(就绪)时会主动回调通知我们.在网络编程中,一般都是基于Reactor线程 ...

  7. Apache Spark源码剖析

    Apache Spark源码剖析(全面系统介绍Spark源码,提供分析源码的实用技巧和合理的阅读顺序,充分了解Spark的设计思想和运行机理) 许鹏 著   ISBN 978-7-121-25420- ...

  8. 基于mybatis-generator-core 1.3.5项目的修订版以及源码剖析

    项目简单说明 mybatis-generator,是根据数据库表.字段反向生成实体类等代码文件.我在国庆时候,没事剖析了mybatis-generator-core源码,写了相当详细的中文注释,可以去 ...

  9. STL"源码"剖析-重点知识总结

    STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1.STL概述 STL提供六大组件,彼此可以组合 ...

随机推荐

  1. BCB6编译LUA5.15成功!

    由于想要在一个原生应用里提供脚本功能,而Python的发布不能不说是一件麻烦事.因为所需要的脚本功能很简单,所以决定试试传说中的Lua. 第一步,下载源码.虽然Lua有提供二进制版本下载,但是因为我是 ...

  2. JS动态特性

    var arr=[]; arr['js']='jquery'; arr['css']='oocss'; var obj={}; for(var i in arr) { obj[i]=arr[i]; } ...

  3. 推荐五款优秀的PHP代码重构工具

    在软件工程学里,重构代码一词通常是指在不改变代码的外部行为情况下而修改源代码.软件重构需要借助工具完成,而重构工具能够修改代码同时修改所有引用该代码的地方.本文收集了五款出色的PHP代码重构工具,以帮 ...

  4. BIRT使用1:简介、概念、元素、报表设计器组成

    前一篇博客对birt进行了一个初探,相信通过上篇博客大家对birt有个初步认识,接下来我们随着下面这张思维导图的展示,进入birt的使用学习. 这一篇博客是第一部分,主要介绍一下birt的简介.概念. ...

  5. 【HDOJ】2890 Longest Repeated subsequence

    后缀数组的应用.和男人八题那个后缀数组差不多. /* 2890 */ #include <iostream> #include <sstream> #include <s ...

  6. win设置壁纸

    默认壁纸图片位置: C:\Windows\Web\Wallpaper\Scenes 你可以自己建文件夹,放自己喜欢的桌面壁纸. 设置壁纸: 桌面右键  ->  个性化 然后点击 “桌面背景” - ...

  7. pku,杨建武:文本挖掘技术

    http://webkdd.org/course/ http://www.icst.pku.edu.cn/lcwm/course/WebDataMining/ http://www.icst.pku. ...

  8. poj3671

    首先容易想到的是LIS,但是n<=30000,所以肯定要优化: 壮哉单调队列又登场了: 然后再找一个最长不上升序列并求两者最大值即可,复杂度O(n logn); 应该说这是解题通法了,但再回头看 ...

  9. APIO2012派遣

    2809: [Apio2012]dispatching Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1196  Solved: 586[Submit ...

  10. python扩展实现方法--python与c混和编程

    前言 需要扩展Python语言的理由: 创建Python扩展的步骤 1. 创建应用程序代码 2. 利用样板来包装代码 a. 包含python的头文件 b. 为每个模块的每一个函数增加一个型如PyObj ...